1 16 17 package org.springframework.web.util; 18 19 import java.util.Collections ; 20 import java.util.HashMap ; 21 import java.util.Map ; 22 23 import javax.servlet.ServletContext ; 24 import javax.servlet.jsp.JspException ; 25 import javax.servlet.jsp.PageContext ; 26 import javax.servlet.jsp.el.ELException ; 27 import javax.servlet.jsp.el.Expression ; 28 29 import org.apache.commons.logging.Log; 30 import org.apache.commons.logging.LogFactory; 31 import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; 32 33 import org.springframework.util.Assert; 34 import org.springframework.util.ClassUtils; 35 36 70 public abstract class ExpressionEvaluationUtils { 71 72 76 public static final String EXPRESSION_CACHE_CONTEXT_PARAM = "cacheJspExpressions"; 77 78 public static final String EXPRESSION_PREFIX = "${"; 79 80 public static final String EXPRESSION_SUFFIX = "}"; 81 82 83 private static final String EXPRESSION_CACHE_FLAG_CONTEXT_ATTR = 84 ExpressionEvaluationUtils.class.getName() + ".CACHE_JSP_EXPRESSIONS"; 85 86 private static final String EXPRESSION_CACHE_MAP_CONTEXT_ATTR = 87 ExpressionEvaluationUtils.class.getName() + ".JSP_EXPRESSION_CACHE"; 88 89 private static final String JSP_20_CLASS_NAME = 90 "javax.servlet.jsp.el.ExpressionEvaluator"; 91 92 private static final String JAKARTA_JSTL_CLASS_NAME = 93 "org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager"; 94 95 96 private static final Log logger = LogFactory.getLog(ExpressionEvaluationUtils.class); 97 98 private static ExpressionEvaluationHelper helper; 99 100 101 static { 102 ClassLoader cl = ExpressionEvaluationUtils.class.getClassLoader(); 103 if (ClassUtils.isPresent(JSP_20_CLASS_NAME, cl)) { 104 logger.debug("Found JSP 2.0 ExpressionEvaluator"); 105 if (ClassUtils.isPresent(JAKARTA_JSTL_CLASS_NAME, cl)) { 106 logger.debug("Found Jakarta JSTL ExpressionEvaluatorManager"); 107 helper = new Jsp20ExpressionEvaluationHelper(new JakartaExpressionEvaluationHelper()); 108 } 109 else { 110 helper = new Jsp20ExpressionEvaluationHelper(new NoExpressionEvaluationHelper()); 111 } 112 } 113 else if (ClassUtils.isPresent(JAKARTA_JSTL_CLASS_NAME, cl)) { 114 logger.debug("Found Jakarta JSTL ExpressionEvaluatorManager"); 115 helper = new JakartaExpressionEvaluationHelper(); 116 } 117 else { 118 logger.debug("JSP expression evaluation not available"); 119 helper = new NoExpressionEvaluationHelper(); 120 } 121 } 122 123 124 130 public static boolean isExpressionLanguage(String value) { 131 return (value != null && value.indexOf(EXPRESSION_PREFIX) != -1); 132 } 133 134 146 public static Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 147 throws JspException { 148 149 if (isExpressionLanguage(attrValue)) { 150 return doEvaluate(attrName, attrValue, resultClass, pageContext); 151 } 152 else if (attrValue != null && resultClass != null && !resultClass.isInstance(attrValue)) { 153 throw new JspException ("Attribute value \"" + attrValue + "\" is neither a JSP EL expression nor " + 154 "assignable to result class [" + resultClass.getName() + "]"); 155 } 156 else { 157 return attrValue; 158 } 159 } 160 161 169 public static Object evaluate(String attrName, String attrValue, PageContext pageContext) 170 throws JspException { 171 172 if (isExpressionLanguage(attrValue)) { 173 return doEvaluate(attrName, attrValue, Object .class, pageContext); 174 } 175 else { 176 return attrValue; 177 } 178 } 179 180 188 public static String evaluateString(String attrName, String attrValue, PageContext pageContext) 189 throws JspException { 190 191 if (isExpressionLanguage(attrValue)) { 192 return (String ) doEvaluate(attrName, attrValue, String .class, pageContext); 193 } 194 else { 195 return attrValue; 196 } 197 } 198 199 207 public static int evaluateInteger(String attrName, String attrValue, PageContext pageContext) 208 throws JspException { 209 210 if (isExpressionLanguage(attrValue)) { 211 return ((Integer ) doEvaluate(attrName, attrValue, Integer .class, pageContext)).intValue(); 212 } 213 else { 214 return Integer.parseInt(attrValue); 215 } 216 } 217 218 226 public static boolean evaluateBoolean(String attrName, String attrValue, PageContext pageContext) 227 throws JspException { 228 229 if (isExpressionLanguage(attrValue)) { 230 return ((Boolean ) doEvaluate(attrName, attrValue, Boolean .class, pageContext)).booleanValue(); 231 } 232 else { 233 return Boolean.valueOf(attrValue).booleanValue(); 234 } 235 } 236 237 238 249 private static Object doEvaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 250 throws JspException { 251 252 Assert.notNull(attrValue, "Attribute value must not be null"); 253 Assert.notNull(resultClass, "Result class must not be null"); 254 Assert.notNull(pageContext, "PageContext must not be null"); 255 256 if (resultClass.isAssignableFrom(String .class)) { 257 StringBuffer resultValue = null; 258 int exprPrefixIndex = -1; 259 int exprSuffixIndex = 0; 260 do { 261 exprPrefixIndex = attrValue.indexOf(EXPRESSION_PREFIX, exprSuffixIndex); 262 if (exprPrefixIndex != -1) { 263 int prevExprSuffixIndex = exprSuffixIndex; 264 exprSuffixIndex = attrValue.indexOf(EXPRESSION_SUFFIX, exprPrefixIndex + EXPRESSION_PREFIX.length()); 265 String expr = null; 266 if (exprSuffixIndex != -1) { 267 exprSuffixIndex += EXPRESSION_SUFFIX.length(); 268 expr = attrValue.substring(exprPrefixIndex, exprSuffixIndex); 269 } 270 else { 271 expr = attrValue.substring(exprPrefixIndex); 272 } 273 if (expr.length() == attrValue.length()) { 274 return helper.evaluate(attrName, attrValue, resultClass, pageContext); 277 } 278 else { 279 if (resultValue == null) { 281 resultValue = new StringBuffer (); 282 } 283 resultValue.append(attrValue.substring(prevExprSuffixIndex, exprPrefixIndex)); 284 resultValue.append(helper.evaluate(attrName, expr, String .class, pageContext)); 285 } 286 } 287 else { 288 if (resultValue == null) { 289 resultValue = new StringBuffer (); 290 } 291 resultValue.append(attrValue.substring(exprSuffixIndex)); 292 } 293 } 294 while (exprPrefixIndex != -1 && exprSuffixIndex != -1); 295 return resultValue.toString(); 296 } 297 298 else { 299 return helper.evaluate(attrName, attrValue, resultClass, pageContext); 300 } 301 } 302 303 310 private static Map getJspExpressionCache(PageContext pageContext) { 311 ServletContext servletContext = pageContext.getServletContext(); 312 Map cacheMap = (Map ) servletContext.getAttribute(EXPRESSION_CACHE_MAP_CONTEXT_ATTR); 313 if (cacheMap == null) { 314 Boolean cacheFlag = (Boolean ) servletContext.getAttribute(EXPRESSION_CACHE_FLAG_CONTEXT_ATTR); 315 if (cacheFlag == null) { 316 cacheFlag = Boolean.valueOf(servletContext.getInitParameter(EXPRESSION_CACHE_CONTEXT_PARAM)); 317 servletContext.setAttribute(EXPRESSION_CACHE_FLAG_CONTEXT_ATTR, cacheFlag); 318 } 319 if (cacheFlag.booleanValue()) { 320 cacheMap = Collections.synchronizedMap(new HashMap ()); 321 servletContext.setAttribute(EXPRESSION_CACHE_MAP_CONTEXT_ATTR, cacheMap); 322 } 323 } 324 return cacheMap; 325 } 326 327 328 331 private static interface ExpressionEvaluationHelper { 332 333 public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 334 throws JspException ; 335 } 336 337 338 342 private static class NoExpressionEvaluationHelper implements ExpressionEvaluationHelper { 343 344 public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 345 throws JspException { 346 347 throw new JspException ( 348 "Neither JSP 2.0 nor Jakarta JSTL available - cannot parse JSP EL expression \"" + attrValue + "\""); 349 } 350 } 351 352 353 358 private static class JakartaExpressionEvaluationHelper implements ExpressionEvaluationHelper { 359 360 public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 361 throws JspException { 362 363 return ExpressionEvaluatorManager.evaluate(attrName, attrValue, resultClass, pageContext); 364 } 365 } 366 367 368 373 private static class Jsp20ExpressionEvaluationHelper implements ExpressionEvaluationHelper { 374 375 private final ExpressionEvaluationHelper fallback; 376 377 private boolean fallbackNecessary = false; 378 379 public Jsp20ExpressionEvaluationHelper(ExpressionEvaluationHelper fallback) { 380 this.fallback = fallback; 381 } 382 383 public Object evaluate(String attrName, String attrValue, Class resultClass, PageContext pageContext) 384 throws JspException { 385 386 if (isFallbackNecessary()) { 387 return this.fallback.evaluate(attrName, attrValue, resultClass, pageContext); 388 } 389 390 try { 391 Map expressionCache = getJspExpressionCache(pageContext); 392 if (expressionCache != null) { 393 ExpressionCacheKey cacheKey = new ExpressionCacheKey(attrValue, resultClass); 395 Expression expr = (Expression ) expressionCache.get(cacheKey); 396 if (expr == null) { 397 expr = pageContext.getExpressionEvaluator().parseExpression(attrValue, resultClass, null); 398 expressionCache.put(cacheKey, expr); 399 } 400 return expr.evaluate(pageContext.getVariableResolver()); 401 } 402 else { 403 return pageContext.getExpressionEvaluator().evaluate( 405 attrValue, resultClass, pageContext.getVariableResolver(), null); 406 } 407 } 408 catch (ELException ex) { 409 throw new JspException ("Parsing of JSP EL expression \"" + attrValue + "\" failed", ex); 410 } 411 catch (LinkageError err) { 412 logger.debug("JSP 2.0 ExpressionEvaluator API present but not implemented - using fallback", err); 413 setFallbackNecessary(); 414 return this.fallback.evaluate(attrName, attrValue, resultClass, pageContext); 415 } 416 } 417 418 private synchronized boolean isFallbackNecessary() { 419 return this.fallbackNecessary; 420 } 421 422 private synchronized void setFallbackNecessary() { 423 this.fallbackNecessary = true; 424 } 425 } 426 427 428 431 private static class ExpressionCacheKey { 432 433 private final String value; 434 private final Class resultClass; 435 private final int hashCode; 436 437 public ExpressionCacheKey(String value, Class resultClass) { 438 this.value = value; 439 this.resultClass = resultClass; 440 this.hashCode = this.value.hashCode() * 29 + this.resultClass.hashCode(); 441 } 442 443 public boolean equals(Object obj) { 444 if (!(obj instanceof ExpressionCacheKey)) { 445 return false; 446 } 447 ExpressionCacheKey other = (ExpressionCacheKey) obj; 448 return (this.value.equals(other.value) && this.resultClass.equals(other.resultClass)); 449 } 450 451 public int hashCode() { 452 return this.hashCode; 453 } 454 } 455 456 } 457 | Popular Tags |