This is an automated email from the ASF dual-hosted git repository.
jengebr pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 9192fc8a84 Adding nonstandard support for c:set and c:remove
9192fc8a84 is described below
commit 9192fc8a849f425444f8dacd3d12595fd566f5d7
Author: John Engebretson <[email protected]>
AuthorDate: Tue Apr 22 19:51:01 2025 +0000
Adding nonstandard support for c:set and c:remove
---
java/org/apache/jasper/EmbeddedServletOptions.java | 12 ++
java/org/apache/jasper/JspC.java | 16 ++
java/org/apache/jasper/Options.java | 8 +
java/org/apache/jasper/compiler/Generator.java | 227 +++++++++++++++++++++
.../apache/jasper/runtime/JspRuntimeLibrary.java | 27 +++
test/jakarta/servlet/jsp/TesterPageContext.java | 12 +-
.../jsp/TesterPageContextWithAttributes.java | 126 ++++++++++++
test/org/apache/jasper/compiler/TestGenerator.java | 86 ++++++++
.../compiler/TestNonstandardTagPerformance.java | 148 ++++++++++++++
.../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, 970 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/jasper/EmbeddedServletOptions.java
b/java/org/apache/jasper/EmbeddedServletOptions.java
index 49ec95b63e..e9d212e89d 100644
--- a/java/org/apache/jasper/EmbeddedServletOptions.java
+++ b/java/org/apache/jasper/EmbeddedServletOptions.java
@@ -223,6 +223,8 @@ public final class EmbeddedServletOptions implements
Options {
private boolean useInstanceManagerForTags = false;
+ private String useNonstandardTagOptimizations;
+
public String getProperty(String name) {
return settings.getProperty(name);
}
@@ -470,6 +472,11 @@ public final class EmbeddedServletOptions implements
Options {
return useInstanceManagerForTags;
}
+ @Override
+ public String getUseNonstandardTagOptimizations() {
+ return useNonstandardTagOptimizations;
+ }
+
/**
* Create an EmbeddedServletOptions object using data available from
ServletConfig and ServletContext.
*
@@ -652,6 +659,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 8417538557..2bbde73f59 100644
--- a/java/org/apache/jasper/JspC.java
+++ b/java/org/apache/jasper/JspC.java
@@ -268,6 +268,8 @@ public class JspC extends Task implements Options {
protected boolean fullstop = false;
protected String[] args;
+ protected String useNonstandardTagOptimizations;
+
public static void main(String[] arg) {
if (arg.length == 0) {
System.out.println(Localizer.getMessage("jspc.usage"));
@@ -995,6 +997,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.
*/
@@ -1722,6 +1733,11 @@ public class JspC extends Task implements Options {
}
}
+ @Override
+ public String getUseNonstandardTagOptimizations() {
+ return useNonstandardTagOptimizations;
+ }
+
private class ProcessFile implements Callable<Void> {
private final String file;
diff --git a/java/org/apache/jasper/Options.java
b/java/org/apache/jasper/Options.java
index 721a66ce88..b0802f8e1c 100644
--- a/java/org/apache/jasper/Options.java
+++ b/java/org/apache/jasper/Options.java
@@ -342,4 +342,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 b7aab2f3af..f14b8554d7 100644
--- a/java/org/apache/jasper/compiler/Generator.java
+++ b/java/org/apache/jasper/compiler/Generator.java
@@ -51,6 +51,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.apache.juli.logging.Log;
@@ -74,6 +75,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;
@@ -106,6 +109,8 @@ class Generator {
private final ELInterpreter elInterpreter;
+ private final Set<String> nonstandardCustomTagNames;
+
private final StringInterpreter stringInterpreter;
/**
@@ -1499,6 +1504,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()) {
@@ -3048,6 +3056,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("(jakarta.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 = "jakarta.servlet.jsp.PageContext.PAGE_SCOPE";
+ } else {
+ switch (scopeAttribute.getValue()) {
+ case "":
+ case "page":
+ scopeValue = "jakarta.servlet.jsp.PageContext.PAGE_SCOPE";
+ break;
+ case "request":
+ scopeValue =
"jakarta.servlet.jsp.PageContext.REQUEST_SCOPE";
+ break;
+ case "session":
+ scopeValue =
"jakarta.servlet.jsp.PageContext.SESSION_SCOPE";
+ break;
+ case "application":
+ scopeValue =
"jakarta.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("(jakarta.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) {
@@ -3190,6 +3411,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 7b584f8a85..fb9af4fd7a 100644
--- a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java
+++ b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java
@@ -25,6 +25,7 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
+import jakarta.el.VariableMapper;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
@@ -964,4 +965,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(jakarta.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/jakarta/servlet/jsp/TesterPageContext.java
b/test/jakarta/servlet/jsp/TesterPageContext.java
index 59814ca097..ea1e44b8cb 100644
--- a/test/jakarta/servlet/jsp/TesterPageContext.java
+++ b/test/jakarta/servlet/jsp/TesterPageContext.java
@@ -29,6 +29,15 @@ import jakarta.servlet.ServletResponse;
import jakarta.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/jakarta/servlet/jsp/TesterPageContextWithAttributes.java
b/test/jakarta/servlet/jsp/TesterPageContextWithAttributes.java
new file mode 100644
index 0000000000..bf93e09493
--- /dev/null
+++ b/test/jakarta/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 jakarta.servlet.jsp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import jakarta.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 c6abab5a1b..459af3e666 100644
--- a/test/org/apache/jasper/compiler/TestGenerator.java
+++ b/test/org/apache/jasper/compiler/TestGenerator.java
@@ -394,6 +394,49 @@ public class TestGenerator extends TomcatBaseTest {
doTestJspId(true);
}
+ @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 doTestJspId(boolean document) throws Exception {
getTomcatInstanceTestWebapp(false, true);
@@ -1061,4 +1104,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..11d74957f9
--- /dev/null
+++ b/test/org/apache/jasper/compiler/TestNonstandardTagPerformance.java
@@ -0,0 +1,148 @@
+/*
+ * 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 jakarta.el.ELContext;
+import jakarta.el.ELManager;
+import jakarta.el.ExpressionFactory;
+import jakarta.servlet.jsp.PageContext;
+import jakarta.servlet.jsp.TesterPageContext;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.apache.jasper.runtime.JspRuntimeLibrary;
+
+public class TestNonstandardTagPerformance {
+ static final long NUM_ITERATIONS = 100000000L;
+
+ static final int NUM_TESTS = 5;
+
+ private ELContext elContext;
+
+ private ExpressionFactory factory;
+
+ private ELManager manager;
+ public PageContext pageContext;
+
+ public jakarta.el.ExpressionFactory _jsp_getExpressionFactory() {
+ return factory;
+ }
+
+ private void newCode(jakarta.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
+ JspRuntimeLibrary.nonstandardSetTag(_jspx_page_context, null,
_jspx_page_context,
+ jakarta.servlet.jsp.PageContext.PAGE_SCOPE);
+ _jspx_page_context.setAttribute("groupName", new Object(),
jakarta.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(jakarta.servlet.jsp.tagext.JspTag
_jspx_th_c_005fwhen_005f11,
+ jakarta.servlet.jsp.PageContext _jspx_page_context) throws
java.lang.Throwable {
+// jakarta.servlet.jsp.PageContext pageContext = _jspx_page_context;
+// jakarta.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((jakarta.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() ==
jakarta.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..bf1469bfe8 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 jakarta.el.ELManager;
+import jakarta.servlet.jsp.PageContext;
+import jakarta.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 43eb0f1137..ad387996d9 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 4424d5e404..c5584c9fe0 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -154,6 +154,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: [email protected]
For additional commands, e-mail: [email protected]