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: [email protected]
For additional commands, e-mail: [email protected]