Author: radu
Date: Thu Oct 13 19:50:19 2016
New Revision: 1764774

URL: http://svn.apache.org/viewvc?rev=1764774&view=rev
Log:
SLING-6146 - SourceIdentifier should not mangle underscore characters

Modified:
    
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
    
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
    
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
    
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
    
sling/trunk/bundles/scripting/sightly/java-compiler/src/main/java/org/apache/sling/scripting/sightly/java/compiler/JavaEscapeUtils.java

Modified: 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java?rev=1764774&r1=1764773&r2=1764774&view=diff
==============================================================================
--- 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
 (original)
+++ 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/SightlyJavaCompilerService.java
 Thu Oct 13 19:50:19 2016
@@ -179,17 +179,16 @@ public class SightlyJavaCompilerService
     }
 
     private Object compileRepositoryJavaClass(ResourceResolver resolver, 
String className) {
-        String pojoPath = 
SourceIdentifier.getScriptName(sightlyEngineConfiguration.getBundleSymbolicName(),
 className) + ".java";
-        Resource pojoResource = resolver.getResource(pojoPath);
+        Resource pojoResource = SourceIdentifier.getPOJOFromFQCN(resolver, 
sightlyEngineConfiguration.getBundleSymbolicName(), className);
         if (pojoResource != null) {
             try {
                 SourceIdentifier sourceIdentifier = new 
SourceIdentifier(sightlyEngineConfiguration, pojoResource.getPath());
                 return compileSource(sourceIdentifier, 
IOUtils.toString(pojoResource.adaptTo(InputStream.class), "UTF-8"));
             } catch (IOException e) {
-                throw new SightlyException(String.format("Unable to compile 
class %s from %s.", className, pojoPath), e);
+                throw new SightlyException(String.format("Unable to compile 
class %s from %s.", className, pojoResource.getPath()), e);
             }
         }
-        throw new SightlyException("Cannot find a a file corresponding to 
class " + className + " in the repository.");
+        throw new SightlyException("Cannot find a file corresponding to class 
" + className + " in the repository.");
     }
 
     @Activate

Modified: 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java?rev=1764774&r1=1764773&r2=1764774&view=diff
==============================================================================
--- 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
 (original)
+++ 
sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifier.java
 Thu Oct 13 19:50:19 2016
@@ -18,11 +18,17 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.engine.compiled;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
 import 
org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
 import org.apache.sling.scripting.sightly.java.compiler.ClassInfo;
 import org.apache.sling.scripting.sightly.java.compiler.JavaEscapeUtils;
@@ -33,7 +39,7 @@ import org.apache.sling.scripting.sightl
  */
 public class SourceIdentifier implements ClassInfo {
 
-    public static final Pattern MANGLED_CHAR_PATTER = 
Pattern.compile("(.*)(__[0-9a-f]{4}__)(.*)");
+    public static final Pattern MANGLED_CHAR_PATTERN = 
Pattern.compile("(.*)(__[0-9a-f]{4}__)(.*)");
 
     private SightlyEngineConfiguration engineConfiguration;
     private String scriptName;
@@ -70,7 +76,7 @@ public class SourceIdentifier implements
             String processingScriptName = scriptName;
             boolean javaFile = scriptName.endsWith(".java");
             if (javaFile) {
-                processingScriptName = scriptName.substring(0, 
scriptName.length() - 5);
+                processingScriptName = scriptName.substring(0, 
scriptName.length() - 5).replaceAll("-", "_");
             }
             if (lastSlashIndex != -1) {
                 packageName = 
JavaEscapeUtils.makeJavaPackage(processingScriptName.substring(0, 
lastSlashIndex));
@@ -92,7 +98,7 @@ public class SourceIdentifier implements
         return fullyQualifiedClassName;
     }
 
-    public static String getScriptName(String slashSubpackage, String 
fullyQualifiedClassName) {
+    public static Resource getPOJOFromFQCN(ResourceResolver resolver, String 
slashSubpackage, String fullyQualifiedClassName) {
         String className = fullyQualifiedClassName;
         StringBuilder pathElements = new StringBuilder("/");
         if (StringUtils.isNotEmpty(slashSubpackage) && 
className.contains(slashSubpackage)) {
@@ -101,7 +107,7 @@ public class SourceIdentifier implements
         String[] classElements = StringUtils.split(className, '.');
         for (int i = 0; i < classElements.length; i++) {
             String classElem = classElements[i];
-            Matcher matcher = MANGLED_CHAR_PATTER.matcher(classElem);
+            Matcher matcher = MANGLED_CHAR_PATTERN.matcher(classElem);
             if (matcher.matches()) {
                 String group = matcher.group(2);
                 char unmangled = JavaEscapeUtils.unmangle(group);
@@ -116,8 +122,8 @@ public class SourceIdentifier implements
                 if (underscoreIndex > -1) {
                     if (underscoreIndex == classElem.length() - 1) {
                         classElem = classElem.substring(0, classElem.length() 
-1);
-                    } else {
-                        classElem = classElem.replaceAll("_", ".");
+                    } else if (underscoreIndex == 0 && 
!Character.isJavaIdentifierStart(classElem.charAt(1))){
+                        classElem = classElem.substring(1);
                     }
                 }
             }
@@ -126,7 +132,102 @@ public class SourceIdentifier implements
                 pathElements.append("/");
             }
         }
-        return pathElements.toString();
+        Set<String> possiblePOJOPaths = 
getPossiblePojoPaths(pathElements.toString() + ".java");
+        for (String possiblePath : possiblePOJOPaths) {
+            Resource r = resolver.getResource(possiblePath);
+            if (r != null) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * For a JCR path obtained from expanding a generated class name this 
method generates all the alternative path names that can be
+     * obtained by expanding the mentioned class' name.
+     *
+     * @param originalPath one of the possible paths
+     * @return a {@link Set} containing all the alternative paths if symbol 
replacement was needed; otherwise the set will contain just
+     * the {@code originalPath}
+     */
+    private static Set<String> getPossiblePojoPaths(String originalPath) {
+        Set<String> possiblePaths = new LinkedHashSet<String>();
+        possiblePaths.add(originalPath);
+        Map<Integer, String> chars = new HashMap<Integer, String>();
+        AmbiguousPathSymbol[] symbols = AmbiguousPathSymbol.values();
+        for (AmbiguousPathSymbol symbol : symbols) {
+            String pathCopy = originalPath.substring(0, 
originalPath.lastIndexOf("/"));
+            int actualIndex = 0;
+            boolean firstPass = true;
+            while (pathCopy.indexOf(symbol.getSymbol()) != -1) {
+                int pos = pathCopy.indexOf(symbol.getSymbol());
+                actualIndex += pos;
+                if (!firstPass) {
+                    actualIndex += 1;
+                }
+                chars.put(actualIndex, symbol.getSymbol().toString());
+                pathCopy = pathCopy.substring(pos + 1);
+                firstPass = false;
+            }
+        }
+        if (chars.size() > 0) {
+            ArrayList<AmbiguousPathSymbol[]> possibleArrangements = new 
ArrayList<AmbiguousPathSymbol[]>();
+            populateArray(possibleArrangements, new 
AmbiguousPathSymbol[chars.size()], 0);
+            Integer[] indexes = chars.keySet().toArray(new 
Integer[chars.size()]);
+            for (AmbiguousPathSymbol[] arrangement : possibleArrangements) {
+                char[] possiblePath = originalPath.toCharArray();
+                for (int i = 0; i < arrangement.length; i++) {
+                    char currentSymbol = arrangement[i].getSymbol();
+                    int currentIndex = indexes[i];
+                    possiblePath[currentIndex] = currentSymbol;
+                }
+                possiblePaths.add(new String(possiblePath));
+            }
+        }
+        return possiblePaths;
+    }
+
+    /**
+     * Given an initial array with its size equal to the number of elements of 
a needed arrangement, this method will generate all
+     * the possible arrangements of values for this array in the provided 
{@code arrayCollection}. The values with which the array is
+     * populated are the {@link AmbiguousPathSymbol} constants.
+     *
+     * @param arrayCollection the collection that will store the arrays
+     * @param symbolsArrangementArray an initial array that will be used for 
collecting the results
+     * @param index the initial index of the array that will be populated 
(needed for recursion purposes; start with 0 for the initial call)
+     */
+    private static void populateArray(ArrayList<AmbiguousPathSymbol[]> 
arrayCollection, AmbiguousPathSymbol[] symbolsArrangementArray, int
+            index) {
+        if (symbolsArrangementArray.length > 0) {
+            if (index == symbolsArrangementArray.length) {
+                arrayCollection.add(symbolsArrangementArray.clone());
+            } else {
+                for (AmbiguousPathSymbol symbol : 
AmbiguousPathSymbol.values()) {
+                    symbolsArrangementArray[index] = symbol;
+                    populateArray(arrayCollection, symbolsArrangementArray, 
index + 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * The {@code AmbiguousPathSymbol} holds symbols that are valid for a JCR 
path but that will get transformed to a "_" to obey the
+     * Java naming conventions.
+     */
+    enum AmbiguousPathSymbol {
+        DASH('-'),
+        UNDERSCORE('_'),
+        POINT('.');
+
+        private Character symbol;
+
+        AmbiguousPathSymbol(Character symbol) {
+            this.symbol = symbol;
+        }
+
+        public Character getSymbol() {
+            return symbol;
+        }
     }
 
 }

Modified: 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java?rev=1764774&r1=1764773&r2=1764774&view=diff
==============================================================================
--- 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
 (original)
+++ 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
 Thu Oct 13 19:50:19 2016
@@ -91,7 +91,7 @@ public class SightlyJavaCompilerServiceT
     @Test
     public void testGetInstanceForCachedPojoFromRepo() throws Exception {
         final String pojoPath = "/apps/my-project/test_components/a/Pojo.java";
-        final String className = 
"apps.my__002d__project.test__005f__components.a.Pojo";
+        final String className = "apps.my_project.test_components.a.Pojo";
         Map<String, Long> slyJavaUseMap = new ConcurrentHashMap<String, 
Long>() {{
             put(className, System.currentTimeMillis());
         }};

Modified: 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java?rev=1764774&r1=1764773&r2=1764774&view=diff
==============================================================================
--- 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
 (original)
+++ 
sling/trunk/bundles/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/engine/compiled/SourceIdentifierTest.java
 Thu Oct 13 19:50:19 2016
@@ -16,11 +16,17 @@
  
******************************************************************************/
 package org.apache.sling.scripting.sightly.impl.engine.compiled;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
 import 
org.apache.sling.scripting.sightly.impl.engine.SightlyEngineConfiguration;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -48,9 +54,40 @@ public class SourceIdentifierTest {
     }
 
     @Test
-    public void testGetScriptName() {
-        assertEquals("/apps/my-project/static-test/foo.html", 
SourceIdentifier.getScriptName(BUNDLE_SYMBOLIC_NAME, BUNDLE_SYMBOLIC_NAME +
-                ".apps.my__002d__project.static__002d__test.foo_html"));
+    public void testGetPOJOFromFQCN() {
+        Map<String, String> expectedScriptNames = new HashMap<String, 
String>() {{
+            put("/apps/a_b_c/d_e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d.e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d-e.f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d.e_f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a-b-c/d-e-f/Pojo.java", "apps.a_b_c.d_e_f.Pojo");
+            put("/apps/a/b/c/Pojo.java", "apps.a.b.c.Pojo");
+        }};
+        for (Map.Entry<String, String> scriptEntry : 
expectedScriptNames.entrySet()) {
+            ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+            Resource resource = Mockito.mock(Resource.class);
+            when(resource.getPath()).thenReturn(scriptEntry.getKey());
+            
when(resolver.getResource(scriptEntry.getKey())).thenReturn(resource);
+            Resource result = SourceIdentifier.getPOJOFromFQCN(resolver, 
BUNDLE_SYMBOLIC_NAME, scriptEntry.getValue());
+            assertNotNull(
+                    String.format("ResourceResolver was expected to find 
resource %s for POJO %s. Got null instead.", scriptEntry.getKey(),
+                            scriptEntry.getValue()), result);
+            assertEquals(scriptEntry.getKey(), result.getPath());
+        }
+    }
+
+    @Test
+    public void testPOJOMangling() {
+        Map<String, String> expectedMangling = new HashMap<String, String>(){{
+            put("/apps/test-static/Pojo.java", "apps.test_static.Pojo");
+            put("/apps/_static/Pojo.java", "apps._static.Pojo");
+            put("/apps/static/Pojo.java", "apps.static_.Pojo");
+            put("/apps/a-b-c/d-e-f/AbcDefPojo.java", 
"apps.a_b_c.d_e_f.AbcDefPojo");
+        }};
+        for (Map.Entry<String, String> manglingEntry : 
expectedMangling.entrySet()) {
+            SourceIdentifier sourceIdentifier = 
getSourceIdentifier(manglingEntry.getKey());
+            assertEquals(manglingEntry.getValue(), 
sourceIdentifier.getFullyQualifiedClassName());
+        }
     }
 
     private SourceIdentifier getSourceIdentifier(String path) {

Modified: 
sling/trunk/bundles/scripting/sightly/java-compiler/src/main/java/org/apache/sling/scripting/sightly/java/compiler/JavaEscapeUtils.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/java-compiler/src/main/java/org/apache/sling/scripting/sightly/java/compiler/JavaEscapeUtils.java?rev=1764774&r1=1764773&r2=1764774&view=diff
==============================================================================
--- 
sling/trunk/bundles/scripting/sightly/java-compiler/src/main/java/org/apache/sling/scripting/sightly/java/compiler/JavaEscapeUtils.java
 (original)
+++ 
sling/trunk/bundles/scripting/sightly/java-compiler/src/main/java/org/apache/sling/scripting/sightly/java/compiler/JavaEscapeUtils.java
 Thu Oct 13 19:50:19 2016
@@ -93,7 +93,7 @@ public class JavaEscapeUtils {
         }
         for (int i = 0; i < identifier.length(); i++) {
             char ch = identifier.charAt(i);
-            if (Character.isJavaIdentifierPart(ch) && ch != '_') {
+            if (Character.isJavaIdentifierPart(ch)) {
                 modifiedIdentifier.append(ch);
             } else if (ch == '.') {
                 modifiedIdentifier.append('_');


Reply via email to