Author: markt Date: Tue Feb 12 14:50:39 2013 New Revision: 1445190 URL: http://svn.apache.org/r1445190 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=54239 Enable applications to use a custom EL interpreter. Based on a patch by Sheldon Shao.
Added: tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java (with props) tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java (with props) tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java (with props) Modified: tomcat/trunk/java/org/apache/jasper/compiler/Generator.java tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_es.properties tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_fr.properties tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_ja.properties tomcat/trunk/webapps/docs/jasper-howto.xml Added: tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java?rev=1445190&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java (added) +++ tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java Tue Feb 12 14:50:39 2013 @@ -0,0 +1,46 @@ +/* + * 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.jasper.compiler; + +import org.apache.jasper.JspCompilationContext; + +/** + * Defines the interface for the expression language interpreter. This allows + * users to provide custom EL interpreter implementations that can optimise + * EL processing for an application by , for example, performing code generation + * for simple expressions. + */ +public interface ELInterpreter { + + /** + * Returns the string representing the code that will be inserted into the + * servlet generated for JSP. The default implementation creates a call to + * {@link org.apache.jasper.runtime.PageContextImpl#proprietaryEvaluate( + * String, Class, javax.servlet.jsp.PageContext, + * org.apache.jasper.runtime.ProtectedFunctionMapper, boolean)} but other + * implementations may produce more optimised code. + * + * @param expression a String containing zero or more "${}" expressions + * @param expectedType the expected type of the interpreted result + * @param fnmapvar Variable pointing to a function map. + * @param xmlEscape True if the result should do XML escaping + * @return a String representing a call to the EL interpreter. + */ + public String interpreterCall(JspCompilationContext context, + boolean isTagFile, String expression, + Class<?> expectedType, String fnmapvar, boolean xmlEscape); +} Propchange: tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreter.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java?rev=1445190&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java (added) +++ tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java Tue Feb 12 14:50:39 2013 @@ -0,0 +1,104 @@ +/* + * 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.jasper.compiler; + +import javax.servlet.ServletContext; + +import org.apache.jasper.JspCompilationContext; + +/** + * Provides {@link ELInterpreter} instances for JSP compilation. + * + * The search order is as follows: + * <ol> + * <li>ELInterpreter instance or implementation class name provided as a + * ServletContext attribute</li> + * <li>Implementation class named in a ServletContext initialisation parameter + * </li> + * <li>Default implementation</li> + * </ol> + */ +public class ELInterpreterFactory { + + public static final String EL_INTERPRETER_CLASS_NAME = + ELInterpreter.class.getName(); + + private static final ELInterpreter DEFAULT_INSTANCE = + new DefaultELInterpreter(); + + + /** + * Obtain the correct EL Interpreter for the given web application. + */ + public static ELInterpreter getELInterpreter(ServletContext context) + throws Exception { + + ELInterpreter result = null; + + // Search for an implementation + // 1. ServletContext attribute (set by application or cached by a + // previous call to this method). + Object attribute = context.getAttribute(EL_INTERPRETER_CLASS_NAME); + if (attribute instanceof ELInterpreter) { + return (ELInterpreter) attribute; + } else if (attribute instanceof String) { + result = createInstance(context, (String) attribute); + } + + // 2. ServletContext init parameter + if (result == null) { + String className = + context.getInitParameter(EL_INTERPRETER_CLASS_NAME); + if (className != null) { + result = createInstance(context, className); + } + } + + // 3. Default + if (result == null) { + result = DEFAULT_INSTANCE; + } + + // Cache the result for next time + context.setAttribute(EL_INTERPRETER_CLASS_NAME, result); + return result; + } + + + private static ELInterpreter createInstance(ServletContext context, + String className) throws Exception { + return (ELInterpreter) context.getClassLoader().loadClass( + className).newInstance(); + } + + + private ELInterpreterFactory() { + // Utility class. Hide default constructor. + } + + + public static class DefaultELInterpreter implements ELInterpreter { + + @Override + public String interpreterCall(JspCompilationContext context, + boolean isTagFile, String expression, + Class<?> expectedType, String fnmapvar, boolean xmlEscape) { + return JspUtil.interpreterCall(isTagFile, expression, expectedType, + fnmapvar, xmlEscape); + } + } +} Propchange: tomcat/trunk/java/org/apache/jasper/compiler/ELInterpreterFactory.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/jasper/compiler/Generator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/Generator.java?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/Generator.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/Generator.java Tue Feb 12 14:50:39 2013 @@ -125,6 +125,8 @@ class Generator { private final DateFormat timestampFormat; + private final ELInterpreter elInterpreter; + /** * @param s * the input string @@ -830,8 +832,8 @@ class Generator { } return v; } else if (attr.isELInterpreterInput()) { - v = JspUtil.interpreterCall(this.isTagFile, v, expectedType, - attr.getEL().getMapName(), false); + v = elInterpreter.interpreterCall(ctxt, this.isTagFile, v, + expectedType, attr.getEL().getMapName(), false); if (encode) { return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(" + v + ", request.getCharacterEncoding())"; @@ -916,9 +918,10 @@ class Generator { n.setBeginJavaLine(out.getJavaLine()); if (!pageInfo.isELIgnored() && (n.getEL() != null)) { out.printil("out.write(" - + JspUtil.interpreterCall(this.isTagFile, n.getType() + - "{" + n.getText() + "}", String.class, - n.getEL().getMapName(), false) + ");"); + + elInterpreter.interpreterCall(ctxt, this.isTagFile, + n.getType() + "{" + n.getText() + "}", + String.class, n.getEL().getMapName(), false) + + ");"); } else { out.printil("out.write(" + quote(n.getType() + "{" + n.getText() + "}") + ");"); @@ -2975,8 +2978,8 @@ class Generator { // run attrValue through the expression interpreter String mapName = (attr.getEL() != null) ? attr.getEL() .getMapName() : null; - attrValue = JspUtil.interpreterCall(this.isTagFile, attrValue, - c[0], mapName, false); + attrValue = elInterpreter.interpreterCall(ctxt, + this.isTagFile, attrValue, c[0], mapName, false); } } else { attrValue = convertString(c[0], attrValue, localName, @@ -3414,7 +3417,7 @@ class Generator { /** * Constructor. */ - Generator(ServletWriter out, Compiler compiler) { + Generator(ServletWriter out, Compiler compiler) throws JasperException { this.out = out; methodsBuffered = new ArrayList<>(); charArrayBuffer = null; @@ -3423,6 +3426,16 @@ class Generator { fragmentHelperClass = new FragmentHelperClass("Helper"); pageInfo = compiler.getPageInfo(); + ELInterpreter elInterpreter = null; + try { + elInterpreter = ELInterpreterFactory.getELInterpreter( + compiler.getCompilationContext().getServletContext()); + } catch (Exception e) { + err.jspError("jsp.error.el_interpreter_class.instantiation", + e.getMessage()); + } + this.elInterpreter = elInterpreter; + /* * Temporary hack. If a JSP page uses the "extends" attribute of the * page directive, the _jspInit() method of the generated servlet class Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Tue Feb 12 14:50:39 2013 @@ -387,3 +387,6 @@ xmlParser.skipBomFail=Failed to skip BOM jsp.tldCache.noTldInJar=No TLD files were found in [{0}]. Consider adding the JAR to the tomcat.util.scan.DefaultJarScanner.jarsToSkip or org.apache.catalina.startup.TldConfig.jarsToSkip property in CATALINA_BASE/conf/catalina.properties file. jsp.tldCache.noTldSummary=At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time. + +#ELInterpreter +jsp.error.el_interpreter_class.instantiation=Failed to load or instantiate ELInterpreter class [{0}] \ No newline at end of file Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_es.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_es.properties?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_es.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_es.properties Tue Feb 12 14:50:39 2013 @@ -370,3 +370,6 @@ jsp.message.jsp_unload_check = Revisando xmlParser.skipBomFail = No pude saltar BOM al analizar flujo de entrada XML jsp.tldCache.noTldInJar = No se han hallado ficheros TLD en [{0}]. Considera a\u00F1adir el JAR a la propiedad tomcat.util.scan.DefaultJarScanner.jarsToSkip en el fichero CATALINA_BASE/conf/catalina.propeperties. jsp.tldCache.noTldSummary = Al menos un JAR, que se ha explorado buscando TLDs, a\u00FAn no conten\u00EDa TLDs. Activar historial de depuraci\u00F3n para este historiador para una completa lista de los JARs que fueron explorados y de los que nos se hall\u00F3 TLDs. Saltarse JARs no necesarios durante la exploraci\u00F3n puede dar lugar a una mejora de tiempo significativa en el arranque y compilaci\u00F3n de JSP . + +#ELInterpreter +jsp.error.el_interpreter_class.instantiation=No se puede cargar la clase ELInterpreter llamada [{0}] \ No newline at end of file Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_fr.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_fr.properties?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_fr.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_fr.properties Tue Feb 12 14:50:39 2013 @@ -211,3 +211,6 @@ jsp.error.attributes.not.allowed = {0} n #jsp.error.jspoutput.nonemptybody= #jsp.error.jspoutput.invalidUse= #jsp.error.invalid.bean= + +#ELInterpreter +jsp.error.el_interpreter_class.instantiation=Impossible de charger ou d''instancier la classe ELInterpreter [{0}] \ No newline at end of file Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_ja.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_ja.properties?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_ja.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings_ja.properties Tue Feb 12 14:50:39 2013 @@ -313,3 +313,5 @@ jsp.error.unbalanced.endtag=\u7d42\u4e86 jsp.error.invalid.bean=useBean\u306e\u30af\u30e9\u30b9\u5c5e\u6027 {0} \u306e\u5024\u304c\u7121\u52b9\u3067\u3059 jsp.error.prefix.use_before_dcl=\u3053\u306e\u30bf\u30b0\u6307\u793a\u5b50\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3001\u3059\u3067\u306b\u30d5\u30a1\u30a4\u30eb {1} \u306e {2} \u884c\u76ee\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 +#ELInterpreter +jsp.error.el_interpreter_class.instantiation=ELInterpreter class\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f [{0}] \ No newline at end of file Added: tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java?rev=1445190&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java (added) +++ tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java Tue Feb 12 14:50:39 2013 @@ -0,0 +1,88 @@ +/* + * 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.jasper.compiler; + +import java.io.File; + +import javax.servlet.ServletContext; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.compiler.ELInterpreterFactory.DefaultELInterpreter; + +public class TestELInterpreterFactory extends TomcatBaseTest { + + public static class SimpleELInterpreter implements ELInterpreter { + + @Override + public String interpreterCall(JspCompilationContext context, + boolean isTagFile, String expression, Class<?> expectedType, + String fnmapvar, boolean xmlEscape) { + return expression; + } + } + + @Test + public void testBug54239() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + Context ctx = tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + tomcat.start(); + + ServletContext context = ctx.getServletContext(); + + ELInterpreter interpreter = + ELInterpreterFactory.getELInterpreter(context); + Assert.assertNotNull(interpreter); + Assert.assertTrue(interpreter instanceof DefaultELInterpreter); + + context.removeAttribute(ELInterpreter.class.getName()); + + context.setAttribute(ELInterpreter.class.getName(), + SimpleELInterpreter.class.getName()); + interpreter = ELInterpreterFactory.getELInterpreter(context); + Assert.assertNotNull(interpreter); + Assert.assertTrue(interpreter instanceof SimpleELInterpreter); + + context.removeAttribute(ELInterpreter.class.getName()); + + SimpleELInterpreter simpleInterpreter = new SimpleELInterpreter(); + context.setAttribute(ELInterpreter.class.getName(), simpleInterpreter); + interpreter = ELInterpreterFactory.getELInterpreter(context); + Assert.assertNotNull(interpreter); + Assert.assertTrue(interpreter instanceof SimpleELInterpreter); + Assert.assertTrue(interpreter == simpleInterpreter); + + context.removeAttribute(ELInterpreter.class.getName()); + + + context.setInitParameter(ELInterpreter.class.getName(), + SimpleELInterpreter.class.getName()); + + interpreter = ELInterpreterFactory.getELInterpreter(context); + Assert.assertNotNull(interpreter); + Assert.assertTrue(interpreter instanceof SimpleELInterpreter); + + context.removeAttribute(ELInterpreter.class.getName()); + } +} Propchange: tomcat/trunk/test/org/apache/jasper/compiler/TestELInterpreterFactory.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/docs/jasper-howto.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/jasper-howto.xml?rev=1445190&r1=1445189&r2=1445190&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/jasper-howto.xml (original) +++ tomcat/trunk/webapps/docs/jasper-howto.xml Tue Feb 12 14:50:39 2013 @@ -380,6 +380,28 @@ depending on the application.</li> </p> </section> +<section name="Optimisation"> +<p> +There are a number of extension points provided within Jasper that enable the +user to optimise the behaviour for their environment. +</p> + +<p> +The first of these extension points is the tag plug-in mechanism. This allows +alternative implementations of tag handlers to be provided for a web application +to use. Tag plug-ins are registered via a <code>tagPlugins.xml</code> file +located under <code>WEB-INF</code>. A sample plug-in for the JSTL is included +with Jasper. +</p> + +<p> +The second extension point is the Expression Language interpreter. Alternative +interpreters may be configured through the <code>ServletContext</code>. See the +<code>ELInterpreterFactory</code> javadoc for details of how to configure an +alternative EL interpreter. +</p> +</section> + </body> </document> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org