This is an automated email from the ASF dual-hosted git repository. jengebr pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 285b8215eb Adding nonstandard support for c:set and c:remove 285b8215eb is described below commit 285b8215eb46e641bf8319c92b2aeb2574db38b9 Author: John Engebretson <jeng...@amazon.com> AuthorDate: Fri Apr 18 13:28:19 2025 +0000 Adding nonstandard support for c:set and c:remove --- java/org/apache/jasper/EmbeddedServletOptions.java | 12 ++ java/org/apache/jasper/JspC.java | 18 ++ java/org/apache/jasper/Options.java | 8 + java/org/apache/jasper/compiler/Generator.java | 227 +++++++++++++++++++++ .../apache/jasper/runtime/JspRuntimeLibrary.java | 27 +++ test/javax/servlet/jsp/TesterPageContext.java | 12 +- .../jsp/TesterPageContextWithAttributes.java | 126 ++++++++++++ test/org/apache/jasper/compiler/TestGenerator.java | 86 ++++++++ .../compiler/TestNonstandardTagPerformance.java | 162 +++++++++++++++ .../jasper/runtime/TestJspRuntimeLibrary.java | 37 ++++ test/webapp/WEB-INF/web.xml | 28 +++ .../webapp/jsp/generator/nonstandard/remove-01.jsp | 26 +++ .../webapp/jsp/generator/nonstandard/remove-02.jsp | 26 +++ .../webapp/jsp/generator/nonstandard/remove-03.jsp | 26 +++ .../webapp/jsp/generator/nonstandard/remove-04.jsp | 26 +++ .../webapp/jsp/generator/nonstandard/remove-05.jsp | 26 +++ test/webapp/jsp/generator/nonstandard/set-01.jsp | 22 ++ test/webapp/jsp/generator/nonstandard/set-02.jsp | 22 ++ test/webapp/jsp/generator/nonstandard/set-03.jsp | 22 ++ test/webapp/jsp/generator/nonstandard/set-04.jsp | 22 ++ test/webapp/jsp/generator/nonstandard/set-05.jsp | 22 ++ webapps/docs/changelog.xml | 5 + 22 files changed, 986 insertions(+), 2 deletions(-) diff --git a/java/org/apache/jasper/EmbeddedServletOptions.java b/java/org/apache/jasper/EmbeddedServletOptions.java index 650edcf2ee..f250941498 100644 --- a/java/org/apache/jasper/EmbeddedServletOptions.java +++ b/java/org/apache/jasper/EmbeddedServletOptions.java @@ -67,6 +67,8 @@ public final class EmbeddedServletOptions implements Options { */ private TrimSpacesOption trimSpaces = TrimSpacesOption.FALSE; + private String useNonstandardTagOptimizations; + /** * Determines whether tag handler pooling is enabled. */ @@ -233,6 +235,11 @@ public final class EmbeddedServletOptions implements Options { } @Override + public String getUseNonstandardTagOptimizations() { + return useNonstandardTagOptimizations; + } + + @Override public boolean isPoolingEnabled() { return isPoolingEnabled; } @@ -578,6 +585,11 @@ public final class EmbeddedServletOptions implements Options { this.classpath = classpath; } + String useNonstandardTagOptimizations = config.getInitParameter("useNonstandardTagOptimizations"); + if (useNonstandardTagOptimizations != null) { + this.useNonstandardTagOptimizations = useNonstandardTagOptimizations; + } + /* * scratchdir */ diff --git a/java/org/apache/jasper/JspC.java b/java/org/apache/jasper/JspC.java index 877873b73a..df980cb499 100644 --- a/java/org/apache/jasper/JspC.java +++ b/java/org/apache/jasper/JspC.java @@ -140,6 +140,7 @@ public class JspC extends Task implements Options { protected static final String SWITCH_QUOTE_ATTRIBUTE_EL = "-quoteAttributeEL"; protected static final String SWITCH_NO_QUOTE_ATTRIBUTE_EL = "-no-quoteAttributeEL"; protected static final String SWITCH_THREAD_COUNT = "-threadCount"; + protected static final String SWITCH_USENONSTANDARD_TAG_OPTIMIZATIONS = "-useNonstandardTagOptimizations"; protected static final String SHOW_SUCCESS = "-s"; protected static final String LIST_ERRORS = "-l"; protected static final int INC_WEBXML = 10; @@ -271,6 +272,7 @@ public class JspC extends Task implements Options { protected int argPos; protected boolean fullstop = false; protected String[] args; + protected String useNonstandardTagOptimizations; public static void main(String[] arg) { if (arg.length == 0) { @@ -403,6 +405,8 @@ public class JspC extends Task implements Options { setQuoteAttributeEL(false); } else if (tok.equals(SWITCH_THREAD_COUNT)) { setThreadCount(nextArg()); + } else if (tok.equals(SWITCH_USENONSTANDARD_TAG_OPTIMIZATIONS)) { + setUseNonstandardTagOptimizations(nextArg()); } else { if (tok.startsWith("-")) { throw new JasperException(Localizer.getMessage("jspc.error.unknownOption", tok)); @@ -1030,6 +1034,15 @@ public class JspC extends Task implements Options { failOnError = b; } + /** + * Sets the set of custom tags to use nonstandard optimizations. + * + * @param useNonstandardTagOptimizations which tags to override + */ + public void setUseNonstandardTagOptimizations(String useNonstandardTagOptimizations) { + this.useNonstandardTagOptimizations = useNonstandardTagOptimizations; + } + /** * @return <code>true</code> if an exception will be thrown in case of a compilation error. */ @@ -1783,4 +1796,9 @@ public class JspC extends Task implements Options { return null; } } + + @Override + public String getUseNonstandardTagOptimizations() { + return useNonstandardTagOptimizations; + } } diff --git a/java/org/apache/jasper/Options.java b/java/org/apache/jasper/Options.java index 16dd8c015d..24564a0004 100644 --- a/java/org/apache/jasper/Options.java +++ b/java/org/apache/jasper/Options.java @@ -255,4 +255,12 @@ public interface Options { default boolean getGeneratedJavaAddTimestamp() { return true; } + + /** + * A string containing a comma-separated list of names to which custom tag implementations should be applied. + * Unknown or unused tag entries are harmless. Generally defined via an init parameter on the JspServlet. + * + * @return which tags to use + */ + String getUseNonstandardTagOptimizations(); } diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java index b854cc86b1..47de5cf089 100644 --- a/java/org/apache/jasper/compiler/Generator.java +++ b/java/org/apache/jasper/compiler/Generator.java @@ -52,6 +52,7 @@ import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.jasper.TrimSpacesOption; import org.apache.jasper.compiler.Node.ChildInfoBase; +import org.apache.jasper.compiler.Node.JspAttribute; import org.apache.jasper.compiler.Node.NamedAttribute; import org.apache.jasper.runtime.JspRuntimeLibrary; import org.xml.sax.Attributes; @@ -85,6 +86,8 @@ class Generator { private static final Pattern BLANK_LINE_PATTERN = Pattern.compile("(\\s*(\\n|\\r)+\\s*)"); + private static final String CORE_LIBS_URI = "http://java.sun.com/jsp/jstl/core"; + private final ServletWriter out; private final ArrayList<GenBuffer> methodsBuffered; @@ -117,6 +120,8 @@ class Generator { private final ELInterpreter elInterpreter; + private final Set<String> nonstandardCustomTagNames; + private final StringInterpreter stringInterpreter; /** @@ -1719,6 +1724,9 @@ class Generator { @Override public void visit(Node.CustomTag n) throws JasperException { + if (visitPotentiallyNonstandardCustomTag(n)) { + return; + } // Use plugin to generate more efficient code if there is one. if (n.useTagPlugin()) { @@ -3263,6 +3271,219 @@ class Generator { return varName; } + + /** + * Determines whether a tag should be handled via nonstandard code (typically + * faster). Considers both configuration and level of support within Tomcat. + * + * Note that Tomcat is free to ignore any case it cannot handle, as long as it + * reports it accurately to the caller by returning false. For example, the + * initial implementation for c:set excludes support for body content. c:set + * tags with body content will be generated with the standard code and tags + * without body content will be generated via non-standard code. + * + * @param n tag + * @param jspAttributes jsp attributes + * @return whether code was generated + * @throws JasperException unexpected error + */ + private boolean visitPotentiallyNonstandardCustomTag(Node.CustomTag n) + throws JasperException { + if (!nonstandardCustomTagNames.contains(n.getQName())) { + // tag is not configured, move along + return false; + } + + // collect the attributes into one Map for further checks + Map<String, JspAttribute> jspAttributes = new HashMap<>(); + if (n.getJspAttributes() != null) { + for (JspAttribute jspAttr : n.getJspAttributes()) { + jspAttributes.put(jspAttr.getLocalName(), jspAttr); + } + } + switch (n.qName) { + case "c:set": + // requires var and value, scope is optional, body is prohibited, value cannot be deferred + if (n.hasEmptyBody() + && jspAttributes.containsKey("var") + && jspAttributes.containsKey("value") + && CORE_LIBS_URI.equals(n.getURI())) { + // verify value is not a deferred expression + String valueText = jspAttributes.get("value").getValue(); + if (valueText.startsWith("#")) { + return false; + } else if (jspAttributes.size() == 2 + || (jspAttributes.size() == 3 && jspAttributes.containsKey("scope"))) { + generateNonstandardSetLogic(n, jspAttributes); + return true; + } + } + break; + case "c:remove": + // requires var, scope is optional, body is prohibited + if (n.hasEmptyBody() + && jspAttributes.containsKey("var") + && CORE_LIBS_URI.equals(n.getURI()) + && (jspAttributes.size() == 1 + || (jspAttributes.size() == 2 + && jspAttributes.containsKey("scope")))) { + generateNonstandardRemoveLogic(n, jspAttributes); + return true; + + } + break; + default: + // This indicates someone configured a tag with no non-standard implementation. + // Harmless, fall back to the standard implementation. + } + return false; + } + + private void generateNonstandardSetLogic(Node.CustomTag n, Map<String, JspAttribute> jspAttributes) + throws JasperException { + String baseVar = createTagVarName(n.getQName(), n.getPrefix(), n.getLocalName()); + String tagMethod = "_jspx_meth_" + baseVar; + ServletWriter outSave = out; + + // generate method call + out.printin(tagMethod); + out.print("("); + out.print("_jspx_page_context"); + out.println(");"); + GenBuffer genBuffer = new GenBuffer(n, n.getBody()); + methodsBuffered.add(genBuffer); + out = genBuffer.getOut(); + + // Generate code for method declaration + methodNesting++; + out.println(); + out.pushIndent(); + out.printin("private void "); + out.print(tagMethod); + out.println("(javax.servlet.jsp.PageContext _jspx_page_context)"); + out.printil(" throws java.lang.Throwable {"); + out.pushIndent(); + // Generated body of method + out.printil("// " + n.getQName()); + + JspAttribute varAttribute = jspAttributes.get("var"); + Mark m = n.getStart(); + out.printil("// " + m.getFile() + "(" + m.getLineNumber() + "," + m.getColumnNumber() + ") " + + varAttribute.getTagAttributeInfo()); + + JspAttribute valueAttribute = jspAttributes.get("value"); + m = n.getStart(); + out.printil("// " + m.getFile() + "(" + m.getLineNumber() + "," + m.getColumnNumber() + ") " + + valueAttribute.getTagAttributeInfo()); + + String varValue = varAttribute.getValue(); + + // get the scope constant at compile-time, where blank means page + String scopeValue = translateScopeToConstant(jspAttributes); + + // translates the specified value attributes into EL-interpretation code using standard logic + String evaluatedAttribute = evaluateAttribute(getTagHandlerInfo(n), valueAttribute, + n, null); + + // call the multi-line logic equivalent of SetTag + out.printil("org.apache.jasper.runtime.JspRuntimeLibrary.nonstandardSetTag(_jspx_page_context, \"" + + varValue + "\", " + evaluatedAttribute + ", " + scopeValue + ");"); + + // Generate end of method + out.popIndent(); + out.printil("}"); + out.popIndent(); + + methodNesting--; + // restore previous writer + out = outSave; + } + + /** + * Compile-time translation of the scope variable into the constant equivalent. Avoids runtime evaluation as + * performed by SetTag. Unspecified scope means page. + * + * @param jspAttributes attributes + * @return equivalent constant from PageContext + */ + private String translateScopeToConstant(Map<String, JspAttribute> jspAttributes) { + String scopeValue; + JspAttribute scopeAttribute = jspAttributes.get("scope"); + if (scopeAttribute == null) { + scopeValue = "javax.servlet.jsp.PageContext.PAGE_SCOPE"; + } else { + switch (scopeAttribute.getValue()) { + case "": + case "page": + scopeValue = "javax.servlet.jsp.PageContext.PAGE_SCOPE"; + break; + case "request": + scopeValue = "javax.servlet.jsp.PageContext.REQUEST_SCOPE"; + break; + case "session": + scopeValue = "javax.servlet.jsp.PageContext.SESSION_SCOPE"; + break; + case "application": + scopeValue = "javax.servlet.jsp.PageContext.APPLICATION_SCOPE"; + break; + default: + throw new IllegalArgumentException(Localizer.getMessage("jsp.error.page.invalid.scope")); + } + } + return scopeValue; + } + + /** + * Generates the code for a non-standard remove. Note that removes w/o a specified scope will remove from all scopes. + * + * @param n tag + * @param jspAttributes attributes + * @throws JasperException unspecified error + */ + private void generateNonstandardRemoveLogic(Node.CustomTag n, Map<String, JspAttribute> jspAttributes) + throws JasperException { + String baseVar = createTagVarName(n.getQName(), n.getPrefix(), n.getLocalName()); + String tagMethod = "_jspx_meth_" + baseVar; + ServletWriter outSave = out; + + // generate method call + out.printin(tagMethod); + out.print("("); + out.print("_jspx_page_context"); + out.println(");"); + GenBuffer genBuffer = new GenBuffer(n, n.getBody()); + methodsBuffered.add(genBuffer); + out = genBuffer.getOut(); + + // Generate code for method declaration + methodNesting++; + out.println(); + out.pushIndent(); + out.printin("private void "); + out.print(tagMethod); + out.println("(javax.servlet.jsp.PageContext pageContext)"); + out.printil(" throws java.lang.Throwable {"); + out.pushIndent(); + // Generated body of method + String varValue = jspAttributes.get("var").getValue(); + JspAttribute scope = jspAttributes.get("scope"); + if (scope == null) { + // c:remove without a scope means remove from all scopes + out.printil("pageContext.removeAttribute(\"" + varValue + "\");"); + } else { + // c:remove with a scope means remove only from the specified scope + String scopeValue = translateScopeToConstant(jspAttributes); + out.printil("pageContext.removeAttribute(\"" + varValue + "\", " + scopeValue + ");"); + } + // Generate end of method + out.popIndent(); + out.printil("}"); + out.popIndent(); + + methodNesting--; + // restore previous writer + out = outSave; + } } private static void generateLocalVariables(ServletWriter out, ChildInfoBase n) { @@ -3405,6 +3626,12 @@ class Generator { } timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); timestampFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + String nonstandardOptionsList = ctxt.getOptions().getUseNonstandardTagOptimizations(); + if (nonstandardOptionsList == null) { + nonstandardCustomTagNames = Collections.emptySet(); + } else { + nonstandardCustomTagNames = new HashSet<>(Arrays.asList(nonstandardOptionsList.split(","))); + } } /** diff --git a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java index 35261c5653..516cf9b10b 100644 --- a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java +++ b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java @@ -24,6 +24,7 @@ import java.lang.reflect.Method; import java.net.URLEncoder; import java.util.Enumeration; +import javax.el.VariableMapper; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -968,4 +969,30 @@ public class JspRuntimeLibrary { } } + + /** + * This method parallels the logic of {@code SetSupport.doEndTag()}. + * + * @param pageContext pageContext + * @param var name of the variable + * @param value value to store + * @param scope scope + */ + public static void nonstandardSetTag(javax.servlet.jsp.PageContext pageContext, String var, Object value, + int scope) { + if (value == null) { + // matches SetTag and removes the key from the specified scope + pageContext.removeAttribute(var, scope); + } else { + if (scope == PageContext.PAGE_SCOPE) { + // matches SetTag and cleans up the VariableMapper + VariableMapper vm = pageContext.getELContext().getVariableMapper(); + if (vm != null) { + vm.setVariable(var, null); + } + } + // does the all-important set of the correct scope + pageContext.setAttribute(var, value, scope); + } + } } diff --git a/test/javax/servlet/jsp/TesterPageContext.java b/test/javax/servlet/jsp/TesterPageContext.java index 6898d4341c..cdbe9c82b5 100644 --- a/test/javax/servlet/jsp/TesterPageContext.java +++ b/test/javax/servlet/jsp/TesterPageContext.java @@ -29,6 +29,15 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpSession; public class TesterPageContext extends PageContext { + private final ELContext elContext; + + public TesterPageContext() { + this.elContext = null; + } + + public TesterPageContext(ELContext elContext) { + this.elContext = elContext; + } @Override public void initialize(Servlet servlet, ServletRequest request, @@ -181,8 +190,7 @@ public class TesterPageContext extends PageContext { @Override public ELContext getELContext() { - // NO-OP - return null; + return elContext; } @Override diff --git a/test/javax/servlet/jsp/TesterPageContextWithAttributes.java b/test/javax/servlet/jsp/TesterPageContextWithAttributes.java new file mode 100644 index 0000000000..20a7733367 --- /dev/null +++ b/test/javax/servlet/jsp/TesterPageContextWithAttributes.java @@ -0,0 +1,126 @@ +/* + * 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 javax.servlet.jsp; + +import java.util.HashMap; +import java.util.Map; + +import javax.el.ELContext; + +import org.apache.jasper.compiler.Localizer; + +public class TesterPageContextWithAttributes extends TesterPageContext { + private final Map<String, Object> applicationAttributes = new HashMap<>(); + private final Map<String, Object> pageAttributes = new HashMap<>(); + private final Map<String, Object> requestAttributes = new HashMap<>(); + private final Map<String, Object> sessionAttributes = new HashMap<>(); + + public TesterPageContextWithAttributes() { + super(); + } + + public TesterPageContextWithAttributes(ELContext elContext) { + super(elContext); + } + + @Override + public Object getAttribute(String name) { + return getAttribute(name, PAGE_SCOPE); + } + + @Override + public Object getAttribute(String name, int scope) { + if (name == null) { + throw new NullPointerException(Localizer.getMessage("jsp.error.attribute.null_name")); + } + + switch (scope) { + case PAGE_SCOPE: + return pageAttributes.get(name); + case REQUEST_SCOPE: + return requestAttributes.get(name); + case SESSION_SCOPE: + return sessionAttributes.get(name); + case APPLICATION_SCOPE : + return applicationAttributes.get(name); + default: + throw new IllegalArgumentException(Localizer.getMessage("jsp.error.page.invalid.scope")); + } + } + + @Override + public void removeAttribute(String name) { + removeAttribute(name, PAGE_SCOPE); + removeAttribute(name, REQUEST_SCOPE); + removeAttribute(name, SESSION_SCOPE); + removeAttribute(name, APPLICATION_SCOPE); + } + + @Override + public void removeAttribute(String name, int scope) { + switch (scope) { + case PageContext.APPLICATION_SCOPE: + applicationAttributes.remove(name); + break; + case PageContext.PAGE_SCOPE: + pageAttributes.remove(name); + break; + case PageContext.REQUEST_SCOPE: + requestAttributes.remove(name); + break; + case PageContext.SESSION_SCOPE: + sessionAttributes.remove(name); + break; + default: + throw new IllegalArgumentException(Localizer.getMessage("jsp.error.page.invalid.scope")); + } + } + + @Override + public void setAttribute(String name, Object value) { + setAttribute(name, value, PAGE_SCOPE); + } + + @Override + public void setAttribute(String name, Object value, int scope) { + if (value == null) { + removeAttribute(name, scope); + } else { + switch (scope) { + case PAGE_SCOPE: + pageAttributes.put(name, value); + break; + + case REQUEST_SCOPE: + requestAttributes.put(name, value); + break; + + case SESSION_SCOPE: + sessionAttributes.put(name, value); + break; + + case APPLICATION_SCOPE: + applicationAttributes.put(name, value); + break; + + default: + throw new IllegalArgumentException(Localizer.getMessage("jsp.error.page.invalid.scope")); + } + } + } + +} diff --git a/test/org/apache/jasper/compiler/TestGenerator.java b/test/org/apache/jasper/compiler/TestGenerator.java index 9baf0a07a4..4c9a57199e 100644 --- a/test/org/apache/jasper/compiler/TestGenerator.java +++ b/test/org/apache/jasper/compiler/TestGenerator.java @@ -1029,6 +1029,49 @@ public class TestGenerator extends TomcatBaseTest { } } + @Test + public void testNonstandardSets() throws Exception { + getTomcatInstanceTestWebapp(true, true); + + // This should break all subsequent requests + ByteChunk body = new ByteChunk(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/set-01.jsp", body, null); + Assert.assertEquals("\n\n\n" + + "pageContext value=testValue\n" + + "request value=null\n" + + "session value=null\n" + + "application value=null", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/set-02.jsp", body, null); + Assert.assertEquals("\n\n\n" + + "pageContext value=testValue\n" + + "request value=null\n" + + "session value=null\n" + + "application value=null", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/set-03.jsp", body, null); + Assert.assertEquals("\n\n\n" + + "pageContext value=null\n" + + "request value=testValue\n" + + "session value=null\n" + + "application value=null", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/set-04.jsp", body, null); + Assert.assertEquals("\n\n\n" + + "pageContext value=null\n" + + "request value=null\n" + + "session value=testValue\n" + + "application value=null", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/set-05.jsp", body, null); + Assert.assertEquals("\n\n\n" + + "pageContext value=null\n" + + "request value=null\n" + + "session value=null\n" + + "application value=testValue", body.toString()); + body.recycle(); + } + private void doTestJsp(String jspName) throws Exception { doTestJsp(jspName, HttpServletResponse.SC_OK); } @@ -1041,4 +1084,47 @@ public class TestGenerator extends TomcatBaseTest { Assert.assertEquals(body.toString(), expectedResponseCode, rc); } + + @Test + public void testNonstandardRemoves() throws Exception { + getTomcatInstanceTestWebapp(true, true); + + // This should break all subsequent requests + ByteChunk body = new ByteChunk(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/remove-01.jsp", body, null); + Assert.assertEquals("\n\n\n\n\n\n\n" + + "pageContext value=null\n" + + "request value=testValue\n" + + "session value=testValue\n" + + "application value=testValue", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/remove-02.jsp", body, null); + Assert.assertEquals("\n\n\n\n\n\n\n" + + "pageContext value=testValue\n" + + "request value=null\n" + + "session value=testValue\n" + + "application value=testValue", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/remove-03.jsp", body, null); + Assert.assertEquals("\n\n\n\n\n\n\n" + + "pageContext value=testValue\n" + + "request value=testValue\n" + + "session value=null\n" + + "application value=testValue", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/remove-04.jsp", body, null); + Assert.assertEquals("\n\n\n\n\n\n\n" + + "pageContext value=testValue\n" + + "request value=testValue\n" + + "session value=testValue\n" + + "application value=null", body.toString()); + body.recycle(); + getUrl("http://localhost:" + getPort() + "/test/jsp/generator/nonstandard/remove-05.jsp", body, null); + Assert.assertEquals("\n\n\n\n\n\n\n" + + "pageContext value=null\n" + + "request value=null\n" + + "session value=null\n" + + "application value=null", body.toString()); + body.recycle(); + } } diff --git a/test/org/apache/jasper/compiler/TestNonstandardTagPerformance.java b/test/org/apache/jasper/compiler/TestNonstandardTagPerformance.java new file mode 100644 index 0000000000..eaeb89131f --- /dev/null +++ b/test/org/apache/jasper/compiler/TestNonstandardTagPerformance.java @@ -0,0 +1,162 @@ +/* + * 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.el.ELContext; +import javax.el.ELManager; +import javax.el.ExpressionFactory; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.TesterPageContext; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import org.apache.jasper.runtime.JspRuntimeLibrary; +//import org.apache.tomcat.InstanceManager; +//import org.apache.tomcat.SimpleInstanceManager; + +/** + * The benchmark requires libraries that are not normally on the build-time classpath (standard tags) so much of this + * code is commented out. Users running the benchmark should uncomment the imports, fields, and methods. + */ +public class TestNonstandardTagPerformance { + static final long NUM_ITERATIONS = 100000000L; + + static final int NUM_TESTS = 5; + + private ELContext elContext; + + private ExpressionFactory factory; + + // uncomment when running the benchmark + // private InstanceManager instanceManager = new SimpleInstanceManager(); + + private ELManager manager; + public PageContext pageContext; + + public javax.el.ExpressionFactory _jsp_getExpressionFactory() { + return factory; + } + + // uncomment when running the benchmark +// private InstanceManager _jsp_getInstanceManager() { +// return instanceManager; +// } + + private void newCode(javax.servlet.jsp.PageContext _jspx_page_context) throws java.lang.Throwable { + JspRuntimeLibrary.nonstandardSetTag(_jspx_page_context, null, _jspx_page_context, + javax.servlet.jsp.PageContext.PAGE_SCOPE); + _jspx_page_context.setAttribute("groupName", new Object(), javax.servlet.jsp.PageContext.PAGE_SCOPE); + } + +// /** +// * This code is stolen from a generated JSP using standard c:set logic, except that the value is replaced by "new +// * Object()". This eliminates the EL cost from the benchmark so we can accurately focus on the c:set performance. +// * +// * @param _jspx_th_c_005fwhen_005f11 parent tag +// * @param _jspx_page_context page context +// * @return whether to continue execution +// * @throws java.lang.Throwable unknown error +// */ +// private boolean oldCode(javax.servlet.jsp.tagext.JspTag _jspx_th_c_005fwhen_005f11, +// javax.servlet.jsp.PageContext _jspx_page_context) throws java.lang.Throwable { +// javax.servlet.jsp.PageContext pageContext = _jspx_page_context; +// javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut(); +// // c:set +// org.apache.taglibs.standard.tag.rt.core.SetTag _jspx_th_c_005fset_005f39 = new org.apache.taglibs.standard.tag.rt.core.SetTag(); +// _jsp_getInstanceManager().newInstance(_jspx_th_c_005fset_005f39); +// try { +// _jspx_th_c_005fset_005f39.setPageContext(_jspx_page_context); +// _jspx_th_c_005fset_005f39.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_c_005fwhen_005f11); +// // /WEB-INF/views/jsp/features/buybox/offerDisplayGroupLayout.jsp(230,12) name = var type = java.lang.String +// // reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null +// // deferredMethod = false methodSignature = null +// _jspx_th_c_005fset_005f39.setVar("groupName"); +// // /WEB-INF/views/jsp/features/buybox/offerDisplayGroupLayout.jsp(230,12) name = value type = +// // javax.el.ValueExpression reqTime = true required = false fragment = false deferredValue = true +// // expectedTypeName = java.lang.Object deferredMethod = false methodSignature = null +// _jspx_th_c_005fset_005f39.setValue(new Object()); +// int _jspx_eval_c_005fset_005f39 = _jspx_th_c_005fset_005f39.doStartTag(); +// if (_jspx_th_c_005fset_005f39.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) { +// return true; +// } +// } finally { +// org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_c_005fset_005f39, +// _jsp_getInstanceManager()); +// } +// return false; +// } + + /** + * This method depends on the availability of org.apache.taglibs.standard.tag.rt.core.SetTag, which is not typically + * available for Tomcat's unit tests. To execute the benchmark correctly, please: + * <ol> + * <li>add a taglibs jar to the classpath</li> + * <li>uncomment the body of {@code oldCode()}</li> + * <li>run the test manually (IDE or command-line)</li> + * <li>use jvm args similar to + * + * <pre> + * -Xmx1g -Xms1g -verbose:gc -XX:+UseParallelGC + * </pre> + * + * </li> + * </ol> + * @throws Throwable generic error + */ + @Ignore + @Test + public void runBenchmark() throws Throwable { + long[] durations = new long[NUM_TESTS]; + for (int i = 0; i < NUM_ITERATIONS / 10; i++) { +// oldCode(null, pageContext); + newCode(pageContext); + } + + for (int i = 0; i < NUM_TESTS; i++) { + long start = System.currentTimeMillis(); + for (long j = 0; j < NUM_ITERATIONS; j++) { +// oldCode(null, pageContext); + } + durations[i] = System.currentTimeMillis() - start; + } + + for (int d = 0; d < durations.length; d++) { + System.out.println("Old: " + d + ". " + durations[d] + "ms"); + } + for (int i = 0; i < NUM_TESTS; i++) { + long start = System.currentTimeMillis(); + for (long j = 0; j < NUM_ITERATIONS; j++) { + newCode(pageContext); + } + durations[i] = System.currentTimeMillis() - start; + } + + for (int d = 0; d < durations.length; d++) { + System.out.println("New: " + d + ". " + durations[d] + "ms"); + } + } + + @Before + public void setupTestVars() { + manager = new ELManager(); + elContext = manager.getELContext(); + factory = ELManager.getExpressionFactory(); + pageContext = new TesterPageContext(elContext); + } +} diff --git a/test/org/apache/jasper/runtime/TestJspRuntimeLibrary.java b/test/org/apache/jasper/runtime/TestJspRuntimeLibrary.java index 7148e860d7..8889da4478 100644 --- a/test/org/apache/jasper/runtime/TestJspRuntimeLibrary.java +++ b/test/org/apache/jasper/runtime/TestJspRuntimeLibrary.java @@ -16,7 +16,12 @@ */ package org.apache.jasper.runtime; +import javax.el.ELManager; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.TesterPageContextWithAttributes; + import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.apache.catalina.startup.TomcatBaseTest; @@ -24,6 +29,8 @@ import org.apache.tomcat.util.buf.ByteChunk; public class TestJspRuntimeLibrary extends TomcatBaseTest { + private PageContext pageContext; + /* * Tests successful conversions */ @@ -140,4 +147,34 @@ public class TestJspRuntimeLibrary extends TomcatBaseTest { private static void assertEcho(String result, String expected) { Assert.assertTrue(result, result.indexOf("<p>" + expected + "</p>") > 0); } + + @Before + public void setupTestVars() { + pageContext = new TesterPageContextWithAttributes((new ELManager()).getELContext()); + } + + @Test + public void testNonstandardSetWithUndefinedScope() { + JspRuntimeLibrary.nonstandardSetTag(pageContext, "var", "value", PageContext.PAGE_SCOPE); + Assert.assertEquals("value", pageContext.getAttribute("var")); + Assert.assertEquals("value", pageContext.getAttribute("var", PageContext.PAGE_SCOPE)); + Assert.assertEquals(null, pageContext.getAttribute("var", PageContext.REQUEST_SCOPE)); + + JspRuntimeLibrary.nonstandardSetTag(pageContext, "var", null, PageContext.PAGE_SCOPE); + Assert.assertEquals(null, pageContext.getAttribute("var")); + + } + + @Test + public void testNonstandardSetWithDefinedScope() { + final int[] scopes = {PageContext.PAGE_SCOPE, PageContext.REQUEST_SCOPE, PageContext.SESSION_SCOPE, PageContext.APPLICATION_SCOPE}; + for (int scope : scopes) { + JspRuntimeLibrary.nonstandardSetTag(pageContext, "var", "value", scope); + Assert.assertEquals("value", pageContext.getAttribute("var", scope)); + + JspRuntimeLibrary.nonstandardSetTag(pageContext, "var", null, scope); + Assert.assertEquals(null, pageContext.getAttribute("var", scope)); + } + + } } diff --git a/test/webapp/WEB-INF/web.xml b/test/webapp/WEB-INF/web.xml index 5179cec113..c78679cc26 100644 --- a/test/webapp/WEB-INF/web.xml +++ b/test/webapp/WEB-INF/web.xml @@ -28,6 +28,11 @@ required. </description> + <servlet-mapping> + <servlet-name>JSP-nonstandard</servlet-name> + <url-pattern>/jsp/generator/nonstandard/*</url-pattern> + </servlet-mapping> + <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> @@ -47,6 +52,29 @@ <load-on-startup>3</load-on-startup> </servlet> + <servlet> + <servlet-name>JSP-nonstandard</servlet-name> + <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> + <init-param> + <param-name>fork</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>xpoweredBy</param-name> + <param-value>false</param-value> + </init-param> + <init-param> + <param-name>useNonstandardTagOptimizations</param-name> + <param-value>c:set,c:remove</param-value> + </init-param> + <!-- Required by /jsp/tagFileInJar.jsp / TestJspCompilationContext --> + <init-param> + <param-name>modificationTestInterval</param-name> + <param-value>0</param-value> + </init-param> + <load-on-startup>3</load-on-startup> + </servlet> + <!-- Bug 49922 --> <filter> <filter-name>Bug49922</filter-name> diff --git a/test/webapp/jsp/generator/nonstandard/remove-01.jsp b/test/webapp/jsp/generator/nonstandard/remove-01.jsp new file mode 100644 index 0000000000..cc2068c5a9 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/remove-01.jsp @@ -0,0 +1,26 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +<c:remove var="testVar" scope="page"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/remove-02.jsp b/test/webapp/jsp/generator/nonstandard/remove-02.jsp new file mode 100644 index 0000000000..74ba79d63f --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/remove-02.jsp @@ -0,0 +1,26 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +<c:remove var="testVar" scope="request"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/remove-03.jsp b/test/webapp/jsp/generator/nonstandard/remove-03.jsp new file mode 100644 index 0000000000..2aa90840c9 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/remove-03.jsp @@ -0,0 +1,26 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +<c:remove var="testVar" scope="session"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/remove-04.jsp b/test/webapp/jsp/generator/nonstandard/remove-04.jsp new file mode 100644 index 0000000000..0fe5ff2f03 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/remove-04.jsp @@ -0,0 +1,26 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +<c:remove var="testVar" scope="application"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/remove-05.jsp b/test/webapp/jsp/generator/nonstandard/remove-05.jsp new file mode 100644 index 0000000000..781a91b1fe --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/remove-05.jsp @@ -0,0 +1,26 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +<c:remove var="testVar"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/set-01.jsp b/test/webapp/jsp/generator/nonstandard/set-01.jsp new file mode 100644 index 0000000000..da6e45d0d4 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/set-01.jsp @@ -0,0 +1,22 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/set-02.jsp b/test/webapp/jsp/generator/nonstandard/set-02.jsp new file mode 100644 index 0000000000..b944135491 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/set-02.jsp @@ -0,0 +1,22 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="page"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/set-03.jsp b/test/webapp/jsp/generator/nonstandard/set-03.jsp new file mode 100644 index 0000000000..7652061487 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/set-03.jsp @@ -0,0 +1,22 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="request"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/set-04.jsp b/test/webapp/jsp/generator/nonstandard/set-04.jsp new file mode 100644 index 0000000000..9f10765dc6 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/set-04.jsp @@ -0,0 +1,22 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="session"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/test/webapp/jsp/generator/nonstandard/set-05.jsp b/test/webapp/jsp/generator/nonstandard/set-05.jsp new file mode 100644 index 0000000000..8b41d435f6 --- /dev/null +++ b/test/webapp/jsp/generator/nonstandard/set-05.jsp @@ -0,0 +1,22 @@ +<%-- + 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. +--%> +<%@ taglib uri = "http://java.sun.com/jsp/jstl/core" prefix = "c" %> +<c:set var="testVar" value="${'testValue'}" scope="application"/> +pageContext value=<%= pageContext.getAttribute("testVar") %> +request value=<%= request.getAttribute("testVar") %> +session value=<%= session.getAttribute("testVar") %> +application value=<%= application.getAttribute("testVar") %> \ No newline at end of file diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index a92d6e6600..3193b83f03 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -129,6 +129,11 @@ <bug>69635</bug>: Add support to <code>jakarta.el.ImportHandler</code> for resolving inner classes. (markt) </fix> + <add> + <pr>842</pr>Add support for optimized execution of c:set and c:remove tags, when + activated via JSP servlet param useNonstandardTagOptimizations. + (jengebr) + </add> </changelog> </subsection> <subsection name="Other"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org