FileDocCategorySizeDatePackage
ELEvaluator.javaAPI DocGlassfish v2 API15422Sat May 05 19:17:26 BST 2007org.apache.taglibs.standard.lang.jstl

ELEvaluator

public class ELEvaluator extends Object

This is the main class for evaluating expression Strings. An expression String is a String that may contain expressions of the form ${...}. Multiple expressions may appear in the same expression String. In such a case, the expression String's value is computed by concatenating the String values of those evaluated expressions and any intervening non-expression text, then converting the resulting String to the expected type using the PropertyEditor mechanism.

In the special case where the expression String is a single expression, the value of the expression String is determined by evaluating the expression, without any intervening conversion to a String.

The evaluator maintains a cache mapping expression Strings to their parsed results. For expression Strings containing no expression elements, it maintains a cache mapping ExpectedType/ExpressionString to parsed value, so that static expression Strings won't have to go through a conversion step every time they are used. All instances of the evaluator share the same cache. The cache may be bypassed by setting a flag on the evaluator's constructor.

The evaluator must be passed a VariableResolver in its constructor. The VariableResolver is used to resolve variable names encountered in expressions, and can also be used to implement "implicit objects" that are always present in the namespace. Different applications will have different policies for variable lookups and implicit objects - these differences can be encapsulated in the VariableResolver passed to the evaluator's constructor.

Most VariableResolvers will need to perform their resolution against some context. For example, a JSP environment needs a PageContext to resolve variables. The evaluate() method takes a generic Object context which is eventually passed to the VariableResolver - the VariableResolver is responsible for casting the context to the proper type.

Once an evaluator instance has been constructed, it may be used multiple times, and may be used by multiple simultaneous Threads. In other words, an evaluator instance is well-suited for use as a singleton.

author
Nathan Abramson - Art Technology Group
author
Shawn Bayern
version
$Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: tcfujii $

Fields Summary
static Map
sCachedExpressionStrings
The mapping from expression String to its parsed form (String, Expression, or ExpressionString)
static Map
sCachedExpectedTypes
The mapping from ExpectedType to Maps mapping literal String to parsed value
static Logger
sLogger
The static Logger
VariableResolver
mResolver
The VariableResolver
boolean
mBypassCache
Flag if the cache should be bypassed
Constructors Summary
public ELEvaluator(VariableResolver pResolver)
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.


  //-------------------------------------
                               
     
  
    mResolver = pResolver;
  
public ELEvaluator(VariableResolver pResolver, boolean pBypassCache)
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

    mResolver = pResolver;
    mBypassCache = pBypassCache;
  
Methods Summary
static java.lang.StringaddEscapes(java.lang.String str)
Used to convert raw characters to their escaped version when these raw version cannot be used as part of an ASCII string literal.

    StringBuffer retval = new StringBuffer ();
    char ch;
    for (int i = 0; i < str.length (); i++) {
      switch (str.charAt (i)) {
	case 0 :
	  continue;
	case '\b":
	  retval.append ("\\b");
	  continue;
	case '\t":
	  retval.append ("\\t");
	  continue;
	case '\n":
	  retval.append ("\\n");
	  continue;
	case '\f":
	  retval.append ("\\f");
	  continue;
	case '\r":
	  retval.append ("\\r");
	  continue;
	default:
	  if ((ch = str.charAt (i)) < 0x20 || ch > 0x7e) {
	    String s = "0000" + Integer.toString (ch, 16);
	    retval.append ("\\u" + s.substring (s.length () - 4, s.length ()));
	  }
	  else {
	    retval.append (ch);
	  }
	  continue;
        }
    }
    return retval.toString ();
  
java.lang.ObjectconvertStaticValueToExpectedType(java.lang.String pValue, java.lang.Class pExpectedType, Logger pLogger)
Converts the given String, specified as a static expression string, to the given expected type. The conversion is cached.

    // See if the value is already of the expected type
    if (pExpectedType == String.class ||
	pExpectedType == Object.class) {
      return pValue;
    }

    // Find the cached value
    Map valueByString = getOrCreateExpectedTypeMap (pExpectedType);
    if (!mBypassCache &&
	valueByString.containsKey (pValue)) {
      return valueByString.get (pValue);
    }
    else {
      // Convert from a String
      Object ret = Coercions.coerce (pValue, pExpectedType, pLogger);
      valueByString.put (pValue, ret);
      return ret;
    }
  
java.lang.ObjectconvertToExpectedType(java.lang.Object pValue, java.lang.Class pExpectedType, Logger pLogger)
Converts the given value to the specified expected type.

    return Coercions.coerce (pValue,
			     pExpectedType,
			     pLogger);
  
public java.lang.Objectevaluate(java.lang.String pExpressionString, java.lang.Object pContext, java.lang.Class pExpectedType, java.util.Map functions, java.lang.String defaultPrefix)
Evaluates the given expression String

param
pExpressionString the expression String to be evaluated
param
pContext the context passed to the VariableResolver for resolving variable names
param
pExpectedType the type to which the evaluated expression should be coerced
return
the expression String evaluated to the given expected type

    return evaluate (pExpressionString,
		     pContext,
		     pExpectedType,
		     functions,
		     defaultPrefix,
		     sLogger);
  
java.lang.Objectevaluate(java.lang.String pExpressionString, java.lang.Object pContext, java.lang.Class pExpectedType, java.util.Map functions, java.lang.String defaultPrefix, Logger pLogger)
Evaluates the given expression string

    // Check for null expression strings
    if (pExpressionString == null) {
      throw new ELException
	(Constants.NULL_EXPRESSION_STRING);
    }

    // Get the parsed version of the expression string
    Object parsedValue = parseExpressionString (pExpressionString);

    // Evaluate differently based on the parsed type
    if (parsedValue instanceof String) {
      // Convert the String, and cache the conversion
      String strValue = (String) parsedValue;
      return convertStaticValueToExpectedType (strValue, 
					       pExpectedType, 
					       pLogger);
    }

    else if (parsedValue instanceof Expression) {
      // Evaluate the expression and convert
      Object value = 
	((Expression) parsedValue).evaluate (pContext,
					     mResolver,
					     functions,
					     defaultPrefix,
					     pLogger);
      return convertToExpectedType (value, 
				    pExpectedType,
				    pLogger);
    }

    else if (parsedValue instanceof ExpressionString) {
      // Evaluate the expression/string list and convert
      String strValue = 
	((ExpressionString) parsedValue).evaluate (pContext, 
						   mResolver,
						   functions,
						   defaultPrefix,
						   pLogger);
      return convertToExpectedType (strValue,
				    pExpectedType,
				    pLogger);
    }

    else {
      // This should never be reached
      return null;
    }
  
static java.lang.StringformatParseException(java.lang.String pExpressionString, org.apache.taglibs.standard.lang.jstl.parser.ParseException pExc)
Formats a ParseException into an error message suitable for displaying on a web page

    // Generate the String of expected tokens
    StringBuffer expectedBuf = new StringBuffer ();
    int maxSize = 0;
    boolean printedOne = false;

    if (pExc.expectedTokenSequences == null)
      return pExc.toString();

    for (int i = 0; i < pExc.expectedTokenSequences.length; i++) {
      if (maxSize < pExc.expectedTokenSequences [i].length) {
        maxSize = pExc.expectedTokenSequences [i].length;
      }
      for (int j = 0; j < pExc.expectedTokenSequences [i].length; j++) {
	if (printedOne) {
	  expectedBuf.append (", ");
	}
        expectedBuf.append 
	  (pExc.tokenImage [pExc.expectedTokenSequences [i] [j]]);
	printedOne = true;
      }
    }
    String expected = expectedBuf.toString ();

    // Generate the String of encountered tokens
    StringBuffer encounteredBuf = new StringBuffer ();
    Token tok = pExc.currentToken.next;
    for (int i = 0; i < maxSize; i++) {
      if (i != 0) encounteredBuf.append (" ");
      if (tok.kind == 0) {
        encounteredBuf.append (pExc.tokenImage [0]);
        break;
      }
      encounteredBuf.append (addEscapes (tok.image));
      tok = tok.next; 
    }
    String encountered = encounteredBuf.toString ();

    // Format the error message
    return MessageFormat.format
      (Constants.PARSE_EXCEPTION,
       new Object [] {
	 expected,
	 encountered,
       });
  
static java.util.MapgetOrCreateExpectedTypeMap(java.lang.Class pExpectedType)
Creates or returns the Map that maps string literals to parsed values for the specified expected type.

    synchronized (sCachedExpectedTypes) {
      Map ret = (Map) sCachedExpectedTypes.get (pExpectedType);
      if (ret == null) {
	ret = Collections.synchronizedMap (new HashMap ());
	sCachedExpectedTypes.put (pExpectedType, ret);
      }
      return ret;
    }
  
public java.lang.StringparseAndRender(java.lang.String pExpressionString)
Parses the given expression string, then converts it back to a String in its canonical form. This is used to test parsing.

    Object val = parseExpressionString (pExpressionString);
    if (val instanceof String) {
      return (String) val;
    }
    else if (val instanceof Expression) {
      return "${" + ((Expression) val).getExpressionString () + "}";
    }
    else if (val instanceof ExpressionString) {
      return ((ExpressionString) val).getExpressionString ();
    }
    else {
      return "";
    }
  
public java.lang.ObjectparseExpressionString(java.lang.String pExpressionString)
Gets the parsed form of the given expression string. If the parsed form is cached (and caching is not bypassed), return the cached form, otherwise parse and cache the value. Returns either a String, Expression, or ExpressionString.

    // See if it's an empty String
    if (pExpressionString.length () == 0) {
      return "";
    }

    // See if it's in the cache
    Object ret = 
      mBypassCache ?
      null :
      sCachedExpressionStrings.get (pExpressionString);

    if (ret == null) {
      // Parse the expression
      Reader r = new StringReader (pExpressionString);
      ELParser parser = new ELParser (r);
      try {
	ret = parser.ExpressionString ();
	sCachedExpressionStrings.put (pExpressionString, ret);
      }
      catch (ParseException exc) {
	throw new ELException 
	  (formatParseException (pExpressionString,
				 exc));
      }
      catch (TokenMgrError exc) {
	// Note - this should never be reached, since the parser is
	// constructed to tokenize any input (illegal inputs get
	// parsed to <BADLY_ESCAPED_STRING_LITERAL> or
	// <ILLEGAL_CHARACTER>
	throw new ELException (exc.getMessage ());
      }
    }
    return ret;