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

radu pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-scripting-sightly.git


The following commit(s) were added to refs/heads/master by this push:
     new afd82b9  SLING-7523 - Java Use object with trailing whitespace in the 
package declaration freezes the SightlyJavaCompilerService
afd82b9 is described below

commit afd82b9e030ad588e39a862fbea78b3adcd610fc
Author: Radu Cotescu <r...@apache.org>
AuthorDate: Tue Mar 6 16:06:52 2018 +0100

    SLING-7523 - Java Use object with trailing whitespace in the package 
declaration freezes the SightlyJavaCompilerService
    
    * extracted Java patterns into a separate class; refactored them, to avoid 
catastrophic backtracking when running
    match operations;
    * added tests for the provided patterns
---
 .../impl/engine/SightlyJavaCompilerService.java    |   4 +-
 .../impl/engine/extension/use/JavaUseProvider.java |   4 +-
 .../scripting/sightly/impl/utils/Patterns.java     |  40 ++++++
 .../scripting/sightly/impl/utils/PatternsTest.java | 157 +++++++++++++++++++++
 4 files changed, 201 insertions(+), 4 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
index 09757e3..0827f9c 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
@@ -42,6 +42,7 @@ import org.apache.sling.commons.compiler.Options;
 import 
org.apache.sling.scripting.api.resource.ScriptingResourceResolverProvider;
 import org.apache.sling.scripting.sightly.SightlyException;
 import 
org.apache.sling.scripting.sightly.impl.engine.compiled.SourceIdentifier;
+import org.apache.sling.scripting.sightly.impl.utils.Patterns;
 import org.apache.sling.scripting.sightly.impl.utils.ScriptUtils;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.osgi.service.component.annotations.Activate;
@@ -62,7 +63,6 @@ import org.slf4j.LoggerFactory;
 public class SightlyJavaCompilerService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(SightlyJavaCompilerService.class);
-    private static final Pattern PACKAGE_DECL_PATTERN = 
Pattern.compile("(\\s*)package\\s+([a-zA-Z_$][a-zA-Z\\d_$]*\\.?)+;");
 
     @Reference
     private ClassLoaderWriter classLoaderWriter = null;
@@ -146,7 +146,7 @@ public class SightlyJavaCompilerService {
             String[] sourceCodeLines = 
sourceCode.split("\\r\\n|[\\n\\x0B\\x0C\\r\\u0085\\u2028\\u2029]");
             boolean foundPackageDeclaration = false;
             for (String line : sourceCodeLines) {
-                Matcher matcher = PACKAGE_DECL_PATTERN.matcher(line);
+                Matcher matcher = 
Patterns.JAVA_PACKAGE_DECLARATION.matcher(line);
                 if (matcher.matches()) {
                 /*
                  * This matching might return false positives like:
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
index e24b19c..13e95ec 100644
--- 
a/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
+++ 
b/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/use/JavaUseProvider.java
@@ -31,6 +31,7 @@ import org.apache.sling.api.scripting.SlingScriptHelper;
 import org.apache.sling.commons.classloader.ClassLoaderWriter;
 import 
org.apache.sling.scripting.sightly.impl.engine.SightlyJavaCompilerService;
 import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils;
+import org.apache.sling.scripting.sightly.impl.utils.Patterns;
 import org.apache.sling.scripting.sightly.pojo.Use;
 import org.apache.sling.scripting.sightly.render.RenderContext;
 import org.apache.sling.scripting.sightly.use.ProviderOutcome;
@@ -64,7 +65,6 @@ public class JavaUseProvider implements UseProvider {
 
     public static final String ADAPTABLE = "adaptable";
     private static final Logger LOG = 
LoggerFactory.getLogger(JavaUseProvider.class);
-    private static final Pattern JAVA_PATTERN = 
Pattern.compile("([[\\p{L}&&[^\\p{Lu}]]_$][\\p{L}\\p{N}_$]*\\.)*[\\p{Lu}_$][\\p{L}\\p{N}_$]*");
 
     @Reference
     private SightlyJavaCompilerService sightlyJavaCompilerService = null;
@@ -74,7 +74,7 @@ public class JavaUseProvider implements UseProvider {
 
     @Override
     public ProviderOutcome provide(String identifier, RenderContext 
renderContext, Bindings arguments) {
-        if (!JAVA_PATTERN.matcher(identifier).matches()) {
+        if (!Patterns.JAVA_CLASS_NAME.matcher(identifier).matches()) {
             LOG.debug("Identifier {} does not match a Java class name 
pattern.", identifier);
             return ProviderOutcome.failure();
         }
diff --git 
a/src/main/java/org/apache/sling/scripting/sightly/impl/utils/Patterns.java 
b/src/main/java/org/apache/sling/scripting/sightly/impl/utils/Patterns.java
new file mode 100644
index 0000000..c034d91
--- /dev/null
+++ b/src/main/java/org/apache/sling/scripting/sightly/impl/utils/Patterns.java
@@ -0,0 +1,40 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.sling.scripting.sightly.impl.utils;
+
+import java.util.regex.Pattern;
+
+public class Patterns {
+
+    private static final String JAVA_IDENTIFIER_REGEX = 
"[\\p{L}\\p{Sc}_][\\p{L}\\p{N}\\p{Sc}_]*";
+
+    /**
+     * Pattern matching valid Java package declarations, according to
+     * <a 
href="https://docs.oracle.com/javase/specs/jls/se7/html/index.html";>The Java® 
Language Specification, 7th edition</a>.
+     */
+    public static final Pattern JAVA_PACKAGE_DECLARATION =
+            Pattern.compile("\\s*package\\s+" + JAVA_IDENTIFIER_REGEX + "(\\." 
+ JAVA_IDENTIFIER_REGEX + ")*\\s*;\\s*");
+
+    /**
+     * Pattern matching Java class names (simple or fully qualified), 
according to
+     * <a 
href="https://docs.oracle.com/javase/specs/jls/se7/html/index.html";>The Java® 
Language Specification, 7th edition</a>.
+     */
+    public static final Pattern JAVA_CLASS_NAME = 
Pattern.compile(JAVA_IDENTIFIER_REGEX + "(\\." + JAVA_IDENTIFIER_REGEX + ")*");
+
+}
diff --git 
a/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PatternsTest.java 
b/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PatternsTest.java
new file mode 100644
index 0000000..80f049d
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/scripting/sightly/impl/utils/PatternsTest.java
@@ -0,0 +1,157 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ 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.sling.scripting.sightly.impl.utils;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+public class PatternsTest {
+
+    private static final int REGEX_MATCH_TIMEOUT = 3;
+
+    @Test
+    public void testJavaPackagePattern() {
+
+        Object[] inputs = new Object[]{
+                "package org.apache.sling.scripting.sightly.impl.utils; ", 
true,
+                "package org.apache.sling.scripting.sightly.impl_utils; ", 
true,
+                "package org.apache.sling.scripting.sightly.impl_utils;", true,
+                "package org.apache.sling.scripting.sightly.impl.utils;", true,
+                "package $org.apache.sling.scripting.sightly.impl.utils;", 
true,
+                "package _org.apache.sling.scripting.sightly.impl.utils;", 
true,
+                "package org.apa_che.sling.scripting.sightly.impl.utils;", 
true,
+                "package org.ap$che.sling.scripting.sightly.impl.utils;", true,
+                "package org.ap4che.$sling._scripting.sightly.impl.utils;", 
true,
+                "package 1org.apache.sling.scripting.sightly.impl.utils;", 
false,
+                "package org.1apache.sling.scripting.sightly.impl.utils;", 
false,
+                "package\torg.apache.sling.scripting.sightly.impl.utils;\t", 
true,
+                "package org.apache.sling.scripting.sightly.impl.utils ; ", 
true,
+        };
+        testPattern(Patterns.JAVA_PACKAGE_DECLARATION, inputs);
+    }
+
+    @Test
+    public void testJavaClassNamePattern() {
+
+        Object[] inputs = new Object[]{
+                "org.apache.sling.scripting.sightly.impl.utils.PatternsTest", 
true,
+                "$org.apache.sling.scripting.sightly.impl.utils.PatternsTest", 
true,
+                "_org.apache.sling.scripting.sightly.impl.utils.PatternsTest", 
true,
+                "PatternsTest", true,
+                "PatternsTest2", true,
+                "PatternsTest ", false,
+                "1PatternsTest", false,
+                "$", true,
+                "_", true,
+                "$_", true,
+                "$_1", true,
+                "package_info", true,
+        };
+        testPattern(Patterns.JAVA_CLASS_NAME, inputs);
+    }
+
+//    @Test
+//    public void testSLING_7523Pattern() {
+//        // pattern from 
org.apache.sling.scripting.sightly.impl.engine.SightlyJavaCompilerService 
before SLING-7523
+//        Pattern PACKAGE_DECL_PATTERN = 
Pattern.compile("(\\s*)package\\s+([a-zA-Z_$][a-zA-Z\\d_$]*\\.?)+;");
+//        Object[] inputs = new Object[]{
+//                "package org.apache.sling.scripting.sightly.impl.utils; ", 
true,
+//                "package org.apache.sling.scripting.sightly.impl_utils; ", 
true,
+//                "package org.apache.sling.scripting.sightly.impl_utils;", 
true,
+//                "package org.apache.sling.scripting.sightly.impl.utils;", 
true,
+//                "package $org.apache.sling.scripting.sightly.impl.utils;", 
true,
+//                "package _org.apache.sling.scripting.sightly.impl.utils;", 
true,
+//                "package org.apa_che.sling.scripting.sightly.impl.utils;", 
true,
+//                "package org.ap$che.sling.scripting.sightly.impl.utils;", 
true,
+//                "package org.ap4che.$sling._scripting.sightly.impl.utils;", 
true,
+//                "package 1org.apache.sling.scripting.sightly.impl.utils;", 
false,
+//                "package org.1apache.sling.scripting.sightly.impl.utils;", 
false,
+//                "package\torg.apache.sling.scripting.sightly.impl.utils;\t", 
true,
+//                "package org.apache.sling.scripting.sightly.impl.utils ; ", 
true,
+//        };
+//        testPattern(PACKAGE_DECL_PATTERN, inputs);
+//    }
+
+    private void testPattern(Pattern pattern, Object[] inputs) {
+        StringBuilder errors = new StringBuilder();
+        ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
+        for (int i = 0; i < inputs.length - 1; i += 2) {
+            String input = (String) inputs[i];
+            boolean expectedMatch = (Boolean) inputs[i + 1];
+            Future<Boolean> future = EXECUTOR_SERVICE.submit(new 
PatternCallable(pattern, input));
+            try {
+                if (expectedMatch != future.get(REGEX_MATCH_TIMEOUT, 
TimeUnit.SECONDS)) {
+                    errors.append(
+                        String.format(
+                                "Pattern '%s' %s '%s'.", pattern, 
expectedMatch ? "was expected to match" : "was not expected to match", input
+                        )
+                    ).append("\n");
+                }
+            } catch (TimeoutException e) {
+                errors.append(
+                        String.format(
+                                "Pattern '%s' is susceptible to catastrophic 
backtracking for input '%s'.",
+                                Patterns.JAVA_PACKAGE_DECLARATION.pattern(),
+                                input
+                        )
+                ).append("\n");
+                future.cancel(true);
+                EXECUTOR_SERVICE.shutdownNow();
+                EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
+            } catch (Exception e) {
+                errors.append(
+                        String.format(
+                                "Unable to test pattern '%s' with input '%s': 
%s.",
+                                Patterns.JAVA_PACKAGE_DECLARATION.pattern(),
+                                input,
+                                e.getMessage()
+                        )
+                ).append("\n");
+            }
+        }
+        if (errors.length() > 0) {
+            fail("\n" + errors.toString());
+        }
+    }
+
+    class PatternCallable implements Callable<Boolean> {
+
+        private Pattern pattern;
+        private String toMatch;
+
+        PatternCallable(Pattern pattern, String toMatch) {
+            this.pattern = pattern;
+            this.toMatch = toMatch;
+        }
+
+        @Override
+        public Boolean call() {
+            return pattern.matcher(toMatch).matches();
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
r...@apache.org.

Reply via email to