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 96f986a  Add extended option to trimSpaces
96f986a is described below

commit 96f986a392f99c6f0d9fe3e18bc605a4f0e0a15d
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Mar 16 17:47:23 2021 +0000

    Add extended option to trimSpaces
---
 java/org/apache/jasper/Options.java                |  7 ++-
 java/org/apache/jasper/TrimSpacesOption.java       |  3 +-
 java/org/apache/jasper/compiler/Compiler.java      |  8 +++-
 java/org/apache/jasper/compiler/Generator.java     | 22 +++++++++
 .../compiler/NewlineReductionServletWriter.java    | 54 ++++++++++++++++++++++
 test/org/apache/jasper/compiler/TestGenerator.java | 52 ++++++++++++++++++++-
 test/webapp/jsp/trim-spaces-extended.jsp           | 49 ++++++++++++++++++++
 webapps/docs/changelog.xml                         |  7 +++
 webapps/docs/jasper-howto.xml                      | 11 +++--
 9 files changed, 204 insertions(+), 9 deletions(-)

diff --git a/java/org/apache/jasper/Options.java 
b/java/org/apache/jasper/Options.java
index 248750a..32e59fd 100644
--- a/java/org/apache/jasper/Options.java
+++ b/java/org/apache/jasper/Options.java
@@ -101,8 +101,11 @@ public interface Options {
      * @return {@link TrimSpacesOption#TRUE} to remove template text that
      *         consists only of whitespace from the output completely,
      *         {@link TrimSpacesOption#SINGLE} to replace such template text
-     *         with a single space or {@link TrimSpacesOption#FALSE} to leave
-     *         such template text unchanged
+     *         with a single space, {@link TrimSpacesOption#FALSE} to leave
+     *         such template text unchanged or {@link 
TrimSpacesOption#EXTENDED}
+     *         to remove template text that consists only of whitespace and to
+     *         replace any sequence of whitespace and new lines within template
+     *         text with a single new line.
      */
     public TrimSpacesOption getTrimSpaces();
 
diff --git a/java/org/apache/jasper/TrimSpacesOption.java 
b/java/org/apache/jasper/TrimSpacesOption.java
index faf7476..2890aa3 100644
--- a/java/org/apache/jasper/TrimSpacesOption.java
+++ b/java/org/apache/jasper/TrimSpacesOption.java
@@ -19,5 +19,6 @@ package org.apache.jasper;
 public enum TrimSpacesOption {
     FALSE,
     TRUE,
-    SINGLE
+    SINGLE,
+    EXTENDED
 }
diff --git a/java/org/apache/jasper/compiler/Compiler.java 
b/java/org/apache/jasper/compiler/Compiler.java
index 81c9fc1..ac6f321 100644
--- a/java/org/apache/jasper/compiler/Compiler.java
+++ b/java/org/apache/jasper/compiler/Compiler.java
@@ -32,6 +32,7 @@ import java.util.Map.Entry;
 import org.apache.jasper.JasperException;
 import org.apache.jasper.JspCompilationContext;
 import org.apache.jasper.Options;
+import org.apache.jasper.TrimSpacesOption;
 import org.apache.jasper.servlet.JspServletWrapper;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -316,7 +317,12 @@ public abstract class Compiler {
                     javaEncoding);
         }
 
-        writer = new ServletWriter(new PrintWriter(osw));
+        if ((ctxt!=null) && 
ctxt.getOptions().getTrimSpaces().equals(TrimSpacesOption.EXTENDED)) {
+            writer = new NewlineReductionServletWriter(new PrintWriter(osw));
+        } else {
+            writer = new ServletWriter(new PrintWriter(osw));
+        }
+
         ctxt.setWriter(writer);
         return writer;
     }
diff --git a/java/org/apache/jasper/compiler/Generator.java 
b/java/org/apache/jasper/compiler/Generator.java
index 7be9edb..e51c93f 100644
--- a/java/org/apache/jasper/compiler/Generator.java
+++ b/java/org/apache/jasper/compiler/Generator.java
@@ -40,6 +40,8 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.el.MethodExpression;
 import javax.el.ValueExpression;
@@ -52,6 +54,7 @@ import org.apache.el.util.JreCompat;
 import org.apache.jasper.Constants;
 import org.apache.jasper.JasperException;
 import org.apache.jasper.JspCompilationContext;
+import org.apache.jasper.TrimSpacesOption;
 import org.apache.jasper.compiler.Node.NamedAttribute;
 import org.apache.jasper.runtime.JspRuntimeLibrary;
 import org.xml.sax.Attributes;
@@ -97,6 +100,10 @@ class Generator {
                     "org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY",
                     "true"));
 
+    private static final Pattern PRE_TAG_PATTERN = 
Pattern.compile("(?s).*(<pre>|</pre>).*");
+
+    private static final Pattern BLANK_LINE_PATTERN = 
Pattern.compile("(\\s*(\\n|\\r)+\\s*)");
+
     private final ServletWriter out;
 
     private final ArrayList<GenBuffer> methodsBuffered;
@@ -2110,6 +2117,21 @@ class Generator {
         public void visit(Node.TemplateText n) throws JasperException {
 
             String text = n.getText();
+            // If the extended option is being used attempt to minimize the
+            // frequency of regex operations.
+            if ((ctxt != null) && 
ctxt.getOptions().getTrimSpaces().equals(TrimSpacesOption.EXTENDED) &&
+                    text.contains("\n")) {
+                // Ensure there are no <pre> or </pre> tags embedded in this
+                // text - if there are, we want to NOT modify the whitespace.
+                Matcher preMatcher = PRE_TAG_PATTERN.matcher(text);
+                if (!preMatcher.matches()) {
+                    Matcher matcher = BLANK_LINE_PATTERN.matcher(text);
+                    String revisedText = matcher.replaceAll("\n");
+                    // Leading and trailing whitespace can be trimmed so remove
+                    // it here as the regex won't remove it.
+                    text = revisedText.trim();
+                }
+            }
 
             int textSize = text.length();
             if (textSize == 0) {
diff --git a/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java 
b/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java
new file mode 100644
index 0000000..ed6fbfe
--- /dev/null
+++ b/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jasper.compiler;
+
+import java.io.PrintWriter;
+
+/**
+ * This class filters duplicate newlines instructions from the compiler output,
+ * and therefore from the runtime JSP. The duplicates typically happen because
+ * the compiler has multiple branches that write them, but they operate
+ * independently and don't realize that the previous output was identical.
+ *
+ * Removing these lines makes the JSP more efficient by executing fewer
+ * operations during runtime.
+ */
+public class NewlineReductionServletWriter extends ServletWriter {
+
+    private static final String NEWLINE_WRITE_TEXT = "out.write('\\n');";
+
+    private boolean lastWriteWasNewline;
+
+    public NewlineReductionServletWriter(PrintWriter writer) {
+        super(writer);
+    }
+
+    @Override
+    public void printil(String s) {
+        if (s.equals(NEWLINE_WRITE_TEXT)) {
+            if (lastWriteWasNewline) {
+                // do nothing
+                return;
+            } else {
+                lastWriteWasNewline = true;
+            }
+        } else {
+            lastWriteWasNewline = false;
+        }
+        super.printil(s);
+    }
+}
\ No newline at end of file
diff --git a/test/org/apache/jasper/compiler/TestGenerator.java 
b/test/org/apache/jasper/compiler/TestGenerator.java
index e370817..b28decc 100644
--- a/test/org/apache/jasper/compiler/TestGenerator.java
+++ b/test/org/apache/jasper/compiler/TestGenerator.java
@@ -17,8 +17,10 @@
 
 package org.apache.jasper.compiler;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.Date;
+import java.util.Scanner;
 
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.JspException;
@@ -30,8 +32,12 @@ import javax.servlet.jsp.tagext.VariableInfo;
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.catalina.Context;
 import org.apache.catalina.LifecycleException;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.jasper.servlet.JasperInitializer;
 import org.apache.tomcat.util.buf.ByteChunk;
 
 public class TestGenerator extends TomcatBaseTest {
@@ -212,7 +218,7 @@ public class TestGenerator extends TomcatBaseTest {
                 response.contains("[1:attribute1: '', attribute2: '']"));
         Assert.assertTrue(response,
                 response.contains("[2:attribute1: '', attribute2: '']"));
-   }
+    }
 
     public static class Bug56529 extends TagSupport {
 
@@ -285,4 +291,48 @@ public class TestGenerator extends TomcatBaseTest {
         System.out.println(result);
         assertEcho(result, "ASYNC");
     }
+
+    @Test
+    public void testTrimSpacesExtended01() throws Exception {
+        doTestTrimSpacesExtended(false);
+    }
+
+    @Test
+    public void testTrimSpacesExtended02() throws Exception {
+        doTestTrimSpacesExtended(true);
+    }
+
+    private void doTestTrimSpacesExtended(boolean removeBlankLines) throws 
Exception {
+        Tomcat tomcat = getTomcatInstance();
+
+        File appDir = new File("test/webapp");
+        Context ctxt = tomcat.addContext("", appDir.getAbsolutePath());
+        ctxt.addServletContainerInitializer(new JasperInitializer(), null);
+
+        Tomcat.initWebappDefaults(ctxt);
+        Wrapper w = (Wrapper) ctxt.findChild("jsp");
+        if (removeBlankLines) {
+            w.addInitParameter("trimSpaces", "extended");
+        }
+
+        tomcat.start();
+
+        ByteChunk res = getUrl("http://localhost:"; + getPort() + 
"/jsp/trim-spaces-extended.jsp");
+
+        String result = res.toString();
+        Scanner scanner = new Scanner(result);
+        int blankLineCount = 0;
+        while (scanner.hasNextLine()) {
+            String line = scanner.nextLine();
+            if (line.length() == 0) {
+                blankLineCount++;
+            }
+        }
+        if (!removeBlankLines && blankLineCount == 0) {
+            Assert.fail("TrimSpaceOptions.EXTENDED not configured but balnk 
lines have been removed");
+        } else if (removeBlankLines && blankLineCount > 0) {
+            Assert.fail("TrimSpaceOptions.EXTENDED does not allow the line to 
be just a new line character");
+        }
+        scanner.close();
+    }
 }
diff --git a/test/webapp/jsp/trim-spaces-extended.jsp 
b/test/webapp/jsp/trim-spaces-extended.jsp
new file mode 100644
index 0000000..817f44f
--- /dev/null
+++ b/test/webapp/jsp/trim-spaces-extended.jsp
@@ -0,0 +1,49 @@
+<%--
+ 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.
+--%>
+<!doctype html>
+<html>
+<head>
+    <title>Apache Tomcat JSP White Space Trim Optimisation 
Configuration</title>
+</head>
+<body>
+
+
+
+<h4>Apache Tomcat JSP white space trim test page</h4>
+<p>If the value of init param jspWhiteSpaceTrimming is set to true, the 
compiler
+trims all the excess white spaces and empty line characters from the JSP files
+and thus reduces build size.</p>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</body>
+</html>
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 777f9f8..bad4825 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -142,6 +142,13 @@
         the list of OSGi exported packages for the Jasper embedded JAR. Patch
         provided by Sokratis Zappis. (markt)
       </fix>
+      <add>
+        Add a new option for the <code>trimSpaces</code> configuration.
+        <code>extended</code> will attempt to remove leading and trailing
+        whitespace from template text and collapse sequences of whitespace and
+        newlines within template text into a single new line. Based on a pull
+        request by kamnani. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>
diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml
index 5efee11..c111074 100644
--- a/webapps/docs/jasper-howto.xml
+++ b/webapps/docs/jasper-howto.xml
@@ -193,10 +193,13 @@ debugging be suppressed? <code>true</code> or 
<code>false</code>, default
 
 <li><strong>trimSpaces</strong> - Should template text that consists entirely 
of
 whitespace be removed from the output (<code>true</code>), replaced with a
-single space (<code>single</code>) or left unchanged (<code>false</code>)? Note
-that if a JSP page or tag file specifies a 
<code>trimDirectiveWhitespaces</code>
-value of <code>true</code>, that will take precedence over this configuration
-setting for that page/tag. Default <code>false</code>.</li>
+single space (<code>single</code>) or left unchanged (<code>false</code>)?
+Alternatively, the <code>extended</code> option will remove leading and 
trailing
+whitespace from template text and collapse sequences of whitespace and newlines
+within the template text to a single new line. Note that if a JSP page or tag
+file specifies a <code>trimDirectiveWhitespaces</code> value of
+<code>true</code>, that will take precedence over this configuration setting 
for
+that page/tag. Default <code>false</code>.</li>
 
 <li><strong>xpoweredBy</strong> - Determines whether X-Powered-By response
 header is added by generated servlet. <code>true</code> or <code>false</code>,


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

Reply via email to