You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2013/07/03 15:17:50 UTC

svn commit: r1499388 - in /tomcat/trunk/java/javax/el: ELContext.java Util.java

Author: markt
Date: Wed Jul  3 13:17:50 2013
New Revision: 1499388

URL: http://svn.apache.org/r1499388
Log:
EL 3.0
Implement new method
Creating ExpressionFactory instances is relatively expensive so they need to be cached but caching them is a potential memory leak since applications may ship their own implementations. Copy the caching approach from the ExpressionFactory implementation.

Modified:
    tomcat/trunk/java/javax/el/ELContext.java
    tomcat/trunk/java/javax/el/Util.java

Modified: tomcat/trunk/java/javax/el/ELContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/ELContext.java?rev=1499388&r1=1499387&r2=1499388&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/ELContext.java (original)
+++ tomcat/trunk/java/javax/el/ELContext.java Wed Jul  3 13:17:50 2013
@@ -155,4 +155,23 @@ public abstract class ELContext {
             }
         }
     }
+
+    /**
+     * @since EL 3.0
+     */
+    public Object convertToType(Object obj, Class<?> type) {
+
+        boolean originalResolved = isPropertyResolved();
+        try {
+            ELResolver resolver = getELResolver();
+            Object result = resolver.convertToType(this, obj, type);
+            if (isPropertyResolved()) {
+                return result;
+            }
+        } finally {
+            setPropertyResolved(originalResolved);
+        }
+
+        return Util.getExpressionFactory().coerceToType(type, type);
+    }
 }

Modified: tomcat/trunk/java/javax/el/Util.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/el/Util.java?rev=1499388&r1=1499387&r2=1499388&view=diff
==============================================================================
--- tomcat/trunk/java/javax/el/Util.java (original)
+++ tomcat/trunk/java/javax/el/Util.java Wed Jul  3 13:17:50 2013
@@ -16,10 +16,16 @@
  */
 package javax.el;
 
+import java.lang.ref.WeakReference;
 import java.text.MessageFormat;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 class Util {
 
@@ -38,6 +44,7 @@ class Util {
         // All other instances of Throwable will be silently swallowed
     }
 
+
     static String message(ELContext context, String name, Object... props) {
         Locale locale = null;
         if (context != null) {
@@ -64,4 +71,112 @@ class Util {
     }
 
 
+    private static final CacheValue nullTcclFactory = new CacheValue();
+    private static final ConcurrentMap<CacheKey, CacheValue> factoryCache =
+            new ConcurrentHashMap<>();
+
+    /**
+     * Provides a per class loader cache of ExpressionFactory instances without
+     * pinning any in memory as that could trigger a memory leak.
+     */
+    static ExpressionFactory getExpressionFactory() {
+
+        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+        CacheValue cacheValue = null;
+        ExpressionFactory factory = null;
+
+        if (tccl == null) {
+            cacheValue = nullTcclFactory;
+        } else {
+            CacheKey key = new CacheKey(tccl);
+            cacheValue = factoryCache.get(key);
+            if (cacheValue == null) {
+                CacheValue newCacheValue = new CacheValue();
+                cacheValue = factoryCache.putIfAbsent(key, newCacheValue);
+                if (cacheValue == null) {
+                    cacheValue = newCacheValue;
+                }
+            }
+        }
+
+        final Lock readLock = cacheValue.getLock().readLock();
+        readLock.lock();
+        try {
+            factory = cacheValue.getExpressionFactory();
+        } finally {
+            readLock.unlock();
+        }
+
+        if (factory == null) {
+            final Lock writeLock = cacheValue.getLock().writeLock();
+            try {
+                writeLock.lock();
+                factory = cacheValue.getExpressionFactory();
+                if (factory == null) {
+                    factory = ExpressionFactory.newInstance();
+                    cacheValue.setExpressionFactory(factory);
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+
+        return factory;
+    }
+
+
+    /**
+     * Key used to cache default ExpressionFactory information per class
+     * loader. The class loader reference is never {@code null}, because
+     * {@code null} tccl is handled separately.
+     */
+    private static class CacheKey {
+        private final int hash;
+        private final WeakReference<ClassLoader> ref;
+
+        public CacheKey(ClassLoader key) {
+            hash = key.hashCode();
+            ref = new WeakReference<>(key);
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (!(obj instanceof CacheKey)) {
+                return false;
+            }
+            ClassLoader thisKey = ref.get();
+            if (thisKey == null) {
+                return false;
+            }
+            return thisKey == ((CacheKey) obj).ref.get();
+        }
+    }
+
+    private static class CacheValue {
+        private final ReadWriteLock lock = new ReentrantReadWriteLock();
+        private WeakReference<ExpressionFactory> ref;
+
+        public CacheValue() {
+        }
+
+        public ReadWriteLock getLock() {
+            return lock;
+        }
+
+        public ExpressionFactory getExpressionFactory() {
+            return ref != null ? ref.get() : null;
+        }
+
+        public void setExpressionFactory(ExpressionFactory factory) {
+            ref = new WeakReference<>(factory);
+        }
+    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org