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