From 2dd7821e404af084c0902b06514751472974ba62 Mon Sep 17 00:00:00 2001 From: markt Date: Wed, 30 Dec 2009 22:20:30 +0000 Subject: [PATCH] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=43819 Implement ExpressionFactory.newInstance() and ensure that Jasper does not refer to org.apache.el directly JSP 2.1 TCK passes with these changes applied Based on a patch by Christoph Beck git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@894720 13f79535-47bb-0310-9956-ffa450edef68 --- java/javax/el/ExpressionFactory.java | 182 ++++++++++++++++++++- java/org/apache/jasper/compiler/JspUtil.java | 3 - java/org/apache/jasper/compiler/PageInfo.java | 4 +- java/org/apache/jasper/compiler/Validator.java | 6 +- .../jasper/runtime/JspApplicationContextImpl.java | 4 +- 5 files changed, 188 insertions(+), 11 deletions(-) diff --git a/java/javax/el/ExpressionFactory.java b/java/javax/el/ExpressionFactory.java index cc8b81031..144d6ca92 100644 --- a/java/javax/el/ExpressionFactory.java +++ b/java/javax/el/ExpressionFactory.java @@ -17,6 +17,16 @@ package javax.el; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Properties; /** @@ -25,6 +35,15 @@ import java.util.Properties; */ public abstract class ExpressionFactory { + private static final String SERVICE_RESOURCE_NAME = + "META-INF/services/javax.el.ExpressionFactory"; + + private static final String SEP = System.getProperty("file.separator"); + private static final String PROPERTY_FILE = + System.getProperty("java.home") + "jre" + SEP + "lib" + SEP + + "el.properties"; + private static final String PROPERTY_NAME = "javax.el.ExpressionFactory"; + public abstract Object coerceToType(Object obj, Class expectedType) throws ELException; @@ -39,13 +58,172 @@ public abstract class ExpressionFactory { String expression, Class expectedReturnType, Class[] expectedParamTypes) throws ELException, NullPointerException; - + + /** + * Create a new {@link ExpressionFactory}. The class to use is determined by + * the following search order: + *
    + *
  1. services API (META-INF/services/javax.el.ExpressionFactory)
  2. + *
  3. $JRE_HOME/lib/el.properties - key javax.el.ExpressionFactory
  4. + *
  5. javax.el.ExpressionFactory
  6. + *
  7. Platform default implementation - + * org.apache.el.ExpressionFactoryImpl
  8. + *
+ * @return + */ public static ExpressionFactory newInstance() { return newInstance(null); } + /** + * Create a new {@link ExpressionFactory} passing in the provided + * {@link Properties}. Search order is the same as {@link #newInstance()}. + * + * @param properties + * @return + */ public static ExpressionFactory newInstance(Properties properties) { - // TODO + String className = null; + ExpressionFactory result = null; + + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + + // First services API + className = getClassNameServices(tccl); + if (className == null) { + // Second el.properties file + className = getClassNameJreDir(); + } + if (className == null) { + // Third system property + className = getClassNameSysProp(); + } + if (className == null) { + // Fourth - default + className = "org.apache.el.ExpressionFactoryImpl"; + } + + try { + Class clazz = null; + if (tccl == null) { + clazz = Class.forName(className); + } else { + clazz = tccl.loadClass(className); + } + Constructor constructor = null; + // Do we need to look for a constructor that will take properties? + if (properties != null) { + try { + constructor = clazz.getConstructor(Properties.class); + } catch (SecurityException se) { + throw new ELException(se); + } catch (NoSuchMethodException nsme) { + // This can be ignored + // This is OK for this constructor not to exist + } + } + if (constructor == null) { + result = (ExpressionFactory) clazz.newInstance(); + } else { + result = + (ExpressionFactory) constructor.newInstance(properties); + } + + } catch (ClassNotFoundException e) { + throw new ELException( + "Unable to find ExpressionFactory of type: " + className, + e); + } catch (InstantiationException e) { + throw new ELException( + "Unable to create ExpressionFactory of type: " + className, + e); + } catch (IllegalAccessException e) { + throw new ELException( + "Unable to create ExpressionFactory of type: " + className, + e); + } catch (IllegalArgumentException e) { + throw new ELException( + "Unable to create ExpressionFactory of type: " + className, + e); + } catch (InvocationTargetException e) { + throw new ELException( + "Unable to create ExpressionFactory of type: " + className, + e); + } + + return result; + } + + private static String getClassNameServices(ClassLoader tccl) { + InputStream is = null; + + if (tccl == null) { + is = ClassLoader.getSystemResourceAsStream(SERVICE_RESOURCE_NAME); + } else { + is = tccl.getResourceAsStream(SERVICE_RESOURCE_NAME); + } + + if (is != null) { + String line = null; + try { + BufferedReader br = + new BufferedReader(new InputStreamReader(is, "UTF-8")); + line = br.readLine(); + if (line != null && line.trim().length() > 0) { + return line.trim(); + } + } catch (UnsupportedEncodingException e) { + // Should never happen with UTF-8 + // If it does - ignore & return null + } catch (IOException e) { + throw new ELException("Failed to read " + SERVICE_RESOURCE_NAME, + e); + } finally { + try { + is.close(); + } catch (IOException ioe) { + // Ignore + } + } + } + + return null; + } + + private static String getClassNameJreDir() { + File file = new File(PROPERTY_FILE); + if (file.canRead()) { + InputStream is = null; + try { + is = new FileInputStream(file); + Properties props = new Properties(); + props.load(is); + String value = props.getProperty(PROPERTY_NAME); + if (value != null && value.trim().length() > 0) { + return value.trim(); + } + } catch (FileNotFoundException e) { + // Should not happen - ignore it if it does + } catch (IOException e) { + throw new ELException("Failed to read " + PROPERTY_FILE, e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // Ignore + } + } + } + } + return null; + } + + private static final String getClassNameSysProp() { + String value = System.getProperty(PROPERTY_NAME); + if (value != null && value.trim().length() > 0) { + return value.trim(); + } return null; } } diff --git a/java/org/apache/jasper/compiler/JspUtil.java b/java/org/apache/jasper/compiler/JspUtil.java index ae21fecef..075efb028 100644 --- a/java/org/apache/jasper/compiler/JspUtil.java +++ b/java/org/apache/jasper/compiler/JspUtil.java @@ -49,9 +49,6 @@ public class JspUtil { private static final String OPEN_EXPR = "<%="; private static final String CLOSE_EXPR = "%>"; - // private static ExpressionEvaluatorImpl expressionEvaluator - // = new ExpressionEvaluatorImpl(); - private static final String javaKeywords[] = { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", diff --git a/java/org/apache/jasper/compiler/PageInfo.java b/java/org/apache/jasper/compiler/PageInfo.java index 051012256..c2b4a308e 100644 --- a/java/org/apache/jasper/compiler/PageInfo.java +++ b/java/org/apache/jasper/compiler/PageInfo.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Set; import java.util.Vector; -import org.apache.el.ExpressionFactoryImpl; import org.apache.jasper.Constants; import org.apache.jasper.JasperException; @@ -76,7 +75,8 @@ class PageInfo { // JSP 2.1 private String deferredSyntaxAllowedAsLiteralValue; private boolean deferredSyntaxAllowedAsLiteral = false; - private ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); + private ExpressionFactory expressionFactory = + ExpressionFactory.newInstance(); private String trimDirectiveWhitespacesValue; private boolean trimDirectiveWhitespaces = false; diff --git a/java/org/apache/jasper/compiler/Validator.java b/java/org/apache/jasper/compiler/Validator.java index 2474456f6..f07e67e7a 100644 --- a/java/org/apache/jasper/compiler/Validator.java +++ b/java/org/apache/jasper/compiler/Validator.java @@ -35,7 +35,6 @@ import javax.servlet.jsp.tagext.TagInfo; import javax.servlet.jsp.tagext.TagLibraryInfo; import javax.servlet.jsp.tagext.ValidationMessage; -import org.apache.el.lang.ELSupport; import org.apache.jasper.JasperException; import org.apache.jasper.el.ELContextImpl; import org.xml.sax.Attributes; @@ -502,6 +501,9 @@ class Validator { new JspUtil.ValidAttribute("doctype-public"), new JspUtil.ValidAttribute("doctype-system") }; + private static final ExpressionFactory EXPRESSION_FACTORY = + ExpressionFactory.newInstance(); + /* * Constructor */ @@ -1160,7 +1162,7 @@ class Validator { } // Check casting try { - ELSupport.checkType(attrs.getValue(i), expectedClass); + EXPRESSION_FACTORY.coerceToType(attrs.getValue(i), expectedClass); } catch (Exception e) { err.jspError (n, "jsp.error.coerce_to_type", diff --git a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java index 0087a9023..9f85da2a2 100644 --- a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java +++ b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java @@ -38,7 +38,6 @@ import javax.servlet.jsp.JspContext; import javax.servlet.jsp.el.ImplicitObjectELResolver; import javax.servlet.jsp.el.ScopedAttributeELResolver; -import org.apache.el.ExpressionFactoryImpl; import org.apache.jasper.Constants; import org.apache.jasper.el.ELContextImpl; @@ -51,7 +50,8 @@ public class JspApplicationContextImpl implements JspApplicationContext { private final static String KEY = JspApplicationContextImpl.class.getName(); - private final static ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); + private final static ExpressionFactory expressionFactory = + ExpressionFactory.newInstance(); private final List contextListeners = new ArrayList(); -- 2.11.0