You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/01/22 12:50:49 UTC

[tomcat] branch 9.0.x updated: BZ 64872 Optimised StringInterpreter for Enum Values

This is an automated email from the ASF dual-hosted git repository.

markt 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 6fc94f2  BZ 64872 Optimised StringInterpreter for Enum Values
6fc94f2 is described below

commit 6fc94f243c4a5890b2d679acd5b7fa0611d7985d
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 25 12:15:23 2020 +0000

    BZ 64872 Optimised StringInterpreter for Enum Values
    
    This is not strictly spec compliant hence it isn't enabled by
    default but it should work for many applicaitons.
    https://bz.apache.org/bugzilla/show_bug.cgi?id=64872
---
 .../optimizations/StringInterpreterEnum.java       |  37 +++++++
 .../optimizations/TestELInterpreterTagSetters.java |   3 +
 .../TestStringInterpreterTagSetters.java           | 120 +++++++++++++++++++++
 test/webapp/bug6nnnn/bug64872-timeunit.jsp         |   3 -
 ...ug64872-timeunit.jsp => bug64872b-timeunit.jsp} |  10 +-
 webapps/docs/jasper-howto.xml                      |   7 ++
 6 files changed, 170 insertions(+), 10 deletions(-)

diff --git a/java/org/apache/jasper/optimizations/StringInterpreterEnum.java b/java/org/apache/jasper/optimizations/StringInterpreterEnum.java
new file mode 100644
index 0000000..b85f339
--- /dev/null
+++ b/java/org/apache/jasper/optimizations/StringInterpreterEnum.java
@@ -0,0 +1,37 @@
+/*
+ * 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.optimizations;
+
+import org.apache.jasper.compiler.StringInterpreterFactory.DefaultStringInterpreter;
+
+/**
+ * Provides an optimised conversion of string values to Enums. It bypasses the
+ * check for registered PropertyEditor.
+ */
+public class StringInterpreterEnum extends DefaultStringInterpreter {
+
+    @Override
+    protected String coerceToOtherType(Class<?> c, String s, boolean isNamedAttribute) {
+        if (c.isEnum() && !isNamedAttribute) {
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            Enum<?> enumValue = Enum.valueOf((Class<? extends Enum>) c, s);
+            return c.getName() + "." + enumValue.name();
+        }
+
+        return null;
+    }
+}
diff --git a/test/org/apache/jasper/optimizations/TestELInterpreterTagSetters.java b/test/org/apache/jasper/optimizations/TestELInterpreterTagSetters.java
index 5a6cf8f..ac66ddd 100644
--- a/test/org/apache/jasper/optimizations/TestELInterpreterTagSetters.java
+++ b/test/org/apache/jasper/optimizations/TestELInterpreterTagSetters.java
@@ -40,6 +40,7 @@ import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.jasper.JspCompilationContext;
 import org.apache.jasper.compiler.ELInterpreter;
 import org.apache.jasper.compiler.ELInterpreterFactory;
+import org.apache.jasper.compiler.StringInterpreter;
 import org.apache.tomcat.util.buf.ByteChunk;
 
 @RunWith(Parameterized.class)
@@ -112,6 +113,8 @@ public class TestELInterpreterTagSetters extends TomcatBaseTest {
         Context ctxt = (Context) tomcat.getHost().findChild("/test");
         ctxt.getServletContext().setAttribute(ELInterpreter.class.getCanonicalName(), elInterpreter);
 
+        ctxt.getServletContext().setAttribute(StringInterpreter.class.getCanonicalName(), new StringInterpreterEnum());
+
         ByteChunk bc = getUrl("http://localhost:" + getPort() + "/test/bug6nnnn/bug64872-" + target + ".jsp");
 
         String actual = bc.toString();
diff --git a/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java b/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java
new file mode 100644
index 0000000..3a75b75
--- /dev/null
+++ b/test/org/apache/jasper/optimizations/TestStringInterpreterTagSetters.java
@@ -0,0 +1,120 @@
+/*
+ * 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.optimizations;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.jasper.compiler.StringInterpreter;
+import org.apache.jasper.compiler.StringInterpreterFactory;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+@RunWith(Parameterized.class)
+public class TestStringInterpreterTagSetters extends TomcatBaseTest {
+
+    @Parameters(name="{index}: {0}")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+
+        StringInterpreter[] stringInterpreters = new StringInterpreter[] {
+                // Warm-up
+                // First call will trigger compilation (and therefore be slower)
+                // Call both to ensure both are warmed up
+                new StringInterpreterWrapper(true, "Enum"),
+                new StringInterpreterWrapper(false, "Default"),
+                // Compare times of these test runs
+                new StringInterpreterWrapper(true, "Enum"),
+                new StringInterpreterWrapper(false, "Default"),
+                };
+
+        for (StringInterpreter stringInterpreter : stringInterpreters) {
+            parameterSets.add(new Object[] { stringInterpreter });
+        }
+        return parameterSets;
+    }
+
+
+    @Parameter(0)
+    public StringInterpreter stringInterpreter;
+
+    @Test
+    public void testTag() throws Exception {
+        Tomcat tomcat = getTomcatInstanceTestWebapp(false, true);
+        Context ctxt = (Context) tomcat.getHost().findChild("/test");
+        ctxt.getServletContext().setAttribute(StringInterpreter.class.getCanonicalName(), stringInterpreter);
+
+        ByteChunk bc = getUrl("http://localhost:" + getPort() + "/test/bug6nnnn/bug64872b-timeunit.jsp");
+
+        String actual = bc.toString();
+
+        Assert.assertTrue(actual, actual.contains("01 The value of foo is [SECONDS]"));
+    }
+
+
+    /*
+     * Wrapper so we can use sensible names in the test labels
+     */
+    private static class StringInterpreterWrapper implements StringInterpreter {
+
+        private final boolean optimised;
+        private final String name;
+        private volatile StringInterpreter stringInterpreter = null;
+
+        public StringInterpreterWrapper(boolean optimised, String name) {
+            this.optimised = optimised;
+            this.name = name;
+        }
+
+        @Override
+        public String convertString(Class<?> c, String s, String attrName, Class<?> propEditorClass,
+                boolean isNamedAttribute) {
+            return getStringInterpreter().convertString(c, s, attrName, propEditorClass, isNamedAttribute) ;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        // Lazy init to avoid LogManager init issues when running parameterized tests
+        private StringInterpreter getStringInterpreter() {
+            if (stringInterpreter == null) {
+                synchronized (this) {
+                    if (stringInterpreter == null) {
+                        if (optimised) {
+                            stringInterpreter = new StringInterpreterEnum();
+                        } else {
+                            stringInterpreter = new StringInterpreterFactory.DefaultStringInterpreter();
+                        }
+                    }
+                }
+            }
+            return stringInterpreter;
+        }
+    }
+}
diff --git a/test/webapp/bug6nnnn/bug64872-timeunit.jsp b/test/webapp/bug6nnnn/bug64872-timeunit.jsp
index e21bc2d..00b71ba 100644
--- a/test/webapp/bug6nnnn/bug64872-timeunit.jsp
+++ b/test/webapp/bug6nnnn/bug64872-timeunit.jsp
@@ -23,9 +23,6 @@
   %>
     <p>01 The value of foo is [<ts:tagTimeUnit foo="${'SECONDS'}" />]</p>
     <p>02 The value of foo is [<ts:tagTimeUnit foo='${"SECONDS"}' />]</p>
-    <%--
-    <p>03 The value of foo is [<ts:tagTimeUnit foo="SECONDS" />]</p>
-     --%>
   <%
   }
   %>
diff --git a/test/webapp/bug6nnnn/bug64872-timeunit.jsp b/test/webapp/bug6nnnn/bug64872b-timeunit.jsp
similarity index 73%
copy from test/webapp/bug6nnnn/bug64872-timeunit.jsp
copy to test/webapp/bug6nnnn/bug64872b-timeunit.jsp
index e21bc2d..679925f 100644
--- a/test/webapp/bug6nnnn/bug64872-timeunit.jsp
+++ b/test/webapp/bug6nnnn/bug64872b-timeunit.jsp
@@ -16,16 +16,12 @@
 --%>
 <%@ taglib uri="http://tomcat.apache.org/tag-setters" prefix="ts" %>
 <html>
-  <head><title>Bug 64872 TimeUnit test case</title></head>
+  <head><title>Bug 64872b TimeUnit test case</title></head>
   <body>
   <%
-  for (int i=0; i < 1000000; i++) {
+  for (int i=0; i < 100000; i++) {
   %>
-    <p>01 The value of foo is [<ts:tagTimeUnit foo="${'SECONDS'}" />]</p>
-    <p>02 The value of foo is [<ts:tagTimeUnit foo='${"SECONDS"}' />]</p>
-    <%--
-    <p>03 The value of foo is [<ts:tagTimeUnit foo="SECONDS" />]</p>
-     --%>
+    <p>01 The value of foo is [<ts:tagTimeUnit foo="SECONDS" />]</p>
   <%
   }
   %>
diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml
index 5d8dd82..5efee11 100644
--- a/webapps/docs/jasper-howto.xml
+++ b/webapps/docs/jasper-howto.xml
@@ -420,6 +420,13 @@ javadoc for details of the optimisations and the impact they have on
 specification compliance.
 </p>
 
+<p>
+An extension point is also provided for coercion of String values to Enums. It
+is provided at
+<code>org.apache.jasper.optimizations.StringInterpreterEnum</code>. See the
+javadoc for details of the optimisations and the impact they have on
+specification compliance.
+</p>
 </section>
 
 </body>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org