--- glassfish-jstl-1.2.0/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java.orig	2005-12-08 09:20:54.000000000 +0800
+++ glassfish-jstl-1.2.0/src/org/apache/taglibs/standard/lang/jstl/ELEvaluator.java	2014-03-18 16:22:13.456952806 +0800
@@ -30,6 +30,7 @@
 import java.text.MessageFormat;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import org.apache.taglibs.standard.lang.jstl.parser.ELParser;
@@ -37,6 +38,8 @@
 import org.apache.taglibs.standard.lang.jstl.parser.Token;
 import org.apache.taglibs.standard.lang.jstl.parser.TokenMgrError;
 
+import javax.servlet.jsp.PageContext;
+
 /**
  *
  * <p>This is the main class for evaluating expression Strings.  An
@@ -98,10 +101,26 @@
   // Member variables
   //-------------------------------------
 
+  /**
+   * Name of configuration setting for maximum number of entries in the
+   * cached expression string map
+   */
+  private static final String EXPR_CACHE_PARAM
+    = "org.apache.taglibs.standard.lang.jstl.exprCacheSize";
+  /**
+   * Default maximum  cache size
+   */
+  private static final int MAX_SIZE = 100;
+   
   /** The mapping from expression String to its parsed form (String,
-      Expression, or ExpressionString) **/
-  static Map sCachedExpressionStrings = 
-    Collections.synchronizedMap (new HashMap ());
+   *  Expression, or ExpressionString)
+   *
+   *  Using LRU Map with a maximum capacity to avoid out of bound map
+   *  growth.
+   *
+   *  NOTE: use LinkedHashmap if a dependency on J2SE 1.4+ is ok
+   */
+  static Map sCachedExpressionStrings = null;
 
   /** The mapping from ExpectedType to Maps mapping literal String to
       parsed value **/
@@ -116,6 +135,10 @@
   /** Flag if the cache should be bypassed **/
   boolean mBypassCache;
 
+  /** The PageContext **/
+  PageContext pageContext;
+
+
   //-------------------------------------
   /**
    *
@@ -132,20 +155,11 @@
 
   //-------------------------------------
   /**
+   * Enable cache bypass
    *
-   * Constructor
-   *
-   * @param pResolver the object that should be used to resolve
-   * variable names encountered in expressions.  If null, all variable
-   * references will resolve to null.
-   *
-   * @param pBypassCache flag indicating if the cache should be
-   * bypassed
+   * @param pBypassCache flag indicating cache should be bypassed
    **/
-  public ELEvaluator (VariableResolver pResolver,
-		      boolean pBypassCache)
-  {
-    mResolver = pResolver;
+  public void setBypassCache(boolean pBypassCache) {
     mBypassCache = pBypassCache;
   }
 
@@ -196,6 +210,9 @@
 	(Constants.NULL_EXPRESSION_STRING);
     }
 
+    // Set the PageContext;
+    pageContext = (PageContext) pContext;  
+
     // Get the parsed version of the expression string
     Object parsedValue = parseExpressionString (pExpressionString);
 
@@ -256,6 +273,10 @@
       return "";
     }
 
+    if (!(mBypassCache) && (sCachedExpressionStrings == null)) {
+      createExpressionStringMap();
+    }
+
     // See if it's in the cache
     Object ret = 
       mBypassCache ?
@@ -268,8 +289,10 @@
       ELParser parser = new ELParser (r);
       try {
 	ret = parser.ExpressionString ();
+        if (!mBypassCache) { 
 	sCachedExpressionStrings.put (pExpressionString, ret);
       }
+      }
       catch (ParseException exc) {
 	throw new ELException 
 	  (formatParseException (pExpressionString,
@@ -350,6 +373,41 @@
     }
   }
 
+  //------------------------------------
+  /**
+   *
+   * Creates LRU map of expression strings. If context parameter
+   * specifying cache size is present use that as the maximum size
+   * of the LRU map otherwise use default.
+   **/
+  private synchronized void createExpressionStringMap () {
+      if (sCachedExpressionStrings != null) {
+        return;
+      }
+
+      final int maxSize;
+      if( (pageContext != null) && (pageContext.getServletContext() != null) ) {
+
+          String value = pageContext.getServletContext().getInitParameter(EXPR_CACHE_PARAM);
+          if (value != null) {
+              maxSize = Integer.valueOf(value);
+          } else {
+              maxSize = MAX_SIZE;
+          }
+
+      } else {
+          maxSize = MAX_SIZE;
+      }
+
+      // fall through if it couldn't find the parameter
+      sCachedExpressionStrings = Collections.synchronizedMap(new LinkedHashMap() {
+          @Override
+          protected boolean removeEldestEntry(Map.Entry eldest) {
+              return size() > maxSize;
+          }
+      });
+  }
+
   //-------------------------------------
   // Formatting ParseException
   //-------------------------------------
