Author: markt Date: Fri Feb 21 10:45:01 2014 New Revision: 1570519 URL: http://svn.apache.org/r1570519 Log: Backport some more EL refactoring in preparation for the fix for https://issues.apache.org/bugzilla/show_bug.cgi?id=56147
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/javax/el/Util.java Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1499388 Modified: tomcat/tc7.0.x/trunk/java/javax/el/Util.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/javax/el/Util.java?rev=1570519&r1=1570518&r2=1570519&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/javax/el/Util.java (original) +++ tomcat/tc7.0.x/trunk/java/javax/el/Util.java Fri Feb 21 10:45:01 2014 @@ -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) { @@ -63,6 +70,116 @@ class Util { } } + + private static final CacheValue nullTcclFactory = new CacheValue(); + private static final ConcurrentMap<CacheKey, CacheValue> factoryCache = + new ConcurrentHashMap<CacheKey, CacheValue>(); + + /** + * 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<ClassLoader>(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<ExpressionFactory>(factory); + } + } + /* * This method duplicates code in org.apache.el.util.ReflectionUtil. When * making changes keep the code in sync. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org