Author: remy.maucherat(a)jboss.com
Date: 2010-11-02 11:40:29 -0400 (Tue, 02 Nov 2010)
New Revision: 1572
Modified:
trunk/java/org/apache/el/lang/ExpressionBuilder.java
trunk/java/org/apache/el/util/ConcurrentCache.java
trunk/java/org/apache/jasper/el/ELContextImpl.java
trunk/java/org/apache/jasper/el/ELResolverImpl.java
trunk/webapps/docs/changelog.xml
Log:
- Fix for JBWEB-185. The cache is now unlimited. Not caching this is probably extremely
bad for actual performance. For specific cases, the system property is there.
- Revert old patch causing a security manager performance drop.
Modified: trunk/java/org/apache/el/lang/ExpressionBuilder.java
===================================================================
--- trunk/java/org/apache/el/lang/ExpressionBuilder.java 2010-10-28 17:00:24 UTC (rev
1571)
+++ trunk/java/org/apache/el/lang/ExpressionBuilder.java 2010-11-02 15:40:29 UTC (rev
1572)
@@ -19,6 +19,9 @@
import java.io.StringReader;
import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.ConcurrentHashMap;
import javax.el.ELContext;
import javax.el.ELException;
@@ -50,8 +53,36 @@
*/
public final class ExpressionBuilder implements NodeVisitor {
- private static final ConcurrentCache cache = new ConcurrentCache(5000);
+ private static final int CACHE_SIZE;
+ private static final String CACHE_SIZE_PROP =
+ "org.apache.el.lang.ExpressionBuilder.CACHE_SIZE";
+ static {
+ if (System.getSecurityManager() == null) {
+ CACHE_SIZE = Integer.parseInt(
+ System.getProperty(CACHE_SIZE_PROP, "-1"));
+ } else {
+ CACHE_SIZE = AccessController.doPrivileged(
+ new PrivilegedAction<Integer>() {
+ @Override
+ public Integer run() {
+ return Integer.valueOf(
+ System.getProperty(CACHE_SIZE_PROP, "-1"));
+ }
+ }).intValue();
+ }
+ if (CACHE_SIZE > 0) {
+ unlimitedCache = null;
+ cache = new ConcurrentCache<String, Node>(CACHE_SIZE);
+ } else {
+ cache = null;
+ unlimitedCache = new ConcurrentHashMap<String, Node>(1024);
+ }
+ }
+
+ private static final ConcurrentCache<String, Node> cache;
+ private static final ConcurrentHashMap<String, Node> unlimitedCache;
+
private FunctionMapper fnMapper;
private VariableMapper varMapper;
@@ -87,7 +118,7 @@
throw new ELException(MessageFactory.get("error.null"));
}
- Node n = (Node) cache.get(expr);
+ Node n = (cache != null) ? cache.get(expr) : unlimitedCache.get(expr);
if (n == null) {
try {
n = (new ELParser(new StringReader(expr)))
@@ -120,7 +151,11 @@
|| n instanceof AstDynamicExpression) {
n = n.jjtGetChild(0);
}
- cache.put(expr, n);
+ if (cache != null) {
+ cache.put(expr, n);
+ } else {
+ unlimitedCache.put(expr, n);
+ }
} catch (ParseException pe) {
throw new ELException("Error Parsing: " + expr, pe);
}
Modified: trunk/java/org/apache/el/util/ConcurrentCache.java
===================================================================
--- trunk/java/org/apache/el/util/ConcurrentCache.java 2010-10-28 17:00:24 UTC (rev 1571)
+++ trunk/java/org/apache/el/util/ConcurrentCache.java 2010-11-02 15:40:29 UTC (rev 1572)
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *
http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.apache.el.util;
import java.util.Map;
@@ -6,34 +22,38 @@
public final class ConcurrentCache<K,V> {
- private final int size;
-
- private final Map<K,V> eden;
-
- private final Map<K,V> longterm;
-
- public ConcurrentCache(int size) {
- this.size = size;
- this.eden = new ConcurrentHashMap<K,V>(size);
- this.longterm = new WeakHashMap<K,V>(size);
- }
-
- public V get(K k) {
- V v = this.eden.get(k);
- if (v == null) {
- v = this.longterm.get(k);
- if (v != null) {
- this.eden.put(k, v);
- }
- }
- return v;
- }
-
- public void put(K k, V v) {
- if (this.eden.size() >= size) {
- this.longterm.putAll(this.eden);
- this.eden.clear();
- }
- this.eden.put(k, v);
- }
+ private final int size;
+
+ private final Map<K,V> eden;
+
+ private final Map<K,V> longterm;
+
+ public ConcurrentCache(int size) {
+ this.size = size;
+ this.eden = new ConcurrentHashMap<K,V>(size);
+ this.longterm = new WeakHashMap<K,V>(size);
+ }
+
+ public V get(K k) {
+ V v = this.eden.get(k);
+ if (v == null) {
+ synchronized (longterm) {
+ v = this.longterm.get(k);
+ }
+ if (v != null) {
+ this.eden.put(k, v);
+ }
+ }
+ return v;
+ }
+
+ public void put(K k, V v) {
+ if (this.eden.size() >= size) {
+ synchronized (longterm) {
+ this.longterm.putAll(this.eden);
+ }
+ this.eden.clear();
+ }
+ this.eden.put(k, v);
+ }
}
Modified: trunk/java/org/apache/jasper/el/ELContextImpl.java
===================================================================
--- trunk/java/org/apache/jasper/el/ELContextImpl.java 2010-10-28 17:00:24 UTC (rev 1571)
+++ trunk/java/org/apache/jasper/el/ELContextImpl.java 2010-11-02 15:40:29 UTC (rev 1572)
@@ -69,7 +69,7 @@
public ELContextImpl() {
this(ELResolverImpl.getDefaultResolver());
- if (Constants.IS_SECURITY_ENABLED) {
+ if (ELResolverImpl.NEW_RESOLVER_INSTANCE &&
Constants.IS_SECURITY_ENABLED) {
functionMapper = new FunctionMapper() {
public Method resolveFunction(String prefix, String localName) {
return null;
Modified: trunk/java/org/apache/jasper/el/ELResolverImpl.java
===================================================================
--- trunk/java/org/apache/jasper/el/ELResolverImpl.java 2010-10-28 17:00:24 UTC (rev
1571)
+++ trunk/java/org/apache/jasper/el/ELResolverImpl.java 2010-11-02 15:40:29 UTC (rev
1572)
@@ -36,9 +36,12 @@
public final class ELResolverImpl extends ELResolver {
- /** @deprecated - Use getDefaultResolver(). Needs to be made private */
- public final static ELResolver DefaultResolver = new CompositeELResolver();
+ public static final boolean NEW_RESOLVER_INSTANCE =
+
Boolean.valueOf(System.getProperty("org.apache.jasper.el.ELResolverImpl.NEW_RESOLVER_INSTANCE",
"false")).booleanValue();
+
+ private final static ELResolver DefaultResolver = new CompositeELResolver();
+
static {
((CompositeELResolver) DefaultResolver).add(new MapELResolver());
((CompositeELResolver) DefaultResolver).add(new ResourceBundleELResolver());
@@ -147,7 +150,7 @@
}
public static ELResolver getDefaultResolver() {
- if (Constants.IS_SECURITY_ENABLED) {
+ if (NEW_RESOLVER_INSTANCE && Constants.IS_SECURITY_ENABLED) {
CompositeELResolver defaultResolver = new CompositeELResolver();
defaultResolver.add(new MapELResolver());
defaultResolver.add(new ResourceBundleELResolver());
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2010-10-28 17:00:24 UTC (rev 1571)
+++ trunk/webapps/docs/changelog.xml 2010-11-02 15:40:29 UTC (rev 1572)
@@ -29,6 +29,14 @@
<fix>
<jboss-jira>JBAS-8579</jboss-jira>: Fix default for tag body content.
(remm)
</fix>
+ <fix>
+ <jira>185</jira>: Fix cache thread safety issue for EL expression
builder.
+ Patch submitted by Takayoshi Kimura. (remm)
+ </fix>
+ <fix>
+ <bug>50192</bug>: Fix regression getting the EL resolver. Tighter
security can
+ be enabled back. (remm)
+ </fix>
</changelog>
</subsection>
</section>