You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2015/01/11 13:11:41 UTC

svn commit: r1650895 - in /sling/trunk/contrib/scripting/sightly/engine: ./ src/main/java/org/apache/sling/scripting/sightly/impl/compiler/ src/test/ src/test/java/ src/test/java/org/ src/test/java/org/apache/ src/test/java/org/apache/sling/ src/test/j...

Author: fmeschbe
Date: Sun Jan 11 12:11:41 2015
New Revision: 1650895

URL: http://svn.apache.org/r1650895
Log:
SLING-4282 [Sightly] Fully qualified Use POJOs are not correctly identified in the repository

Apply patch by Radu Cotescu (thanks alot)

Added:
    sling/trunk/contrib/scripting/sightly/engine/src/test/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java   (with props)
    sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java   (with props)
Modified:
    sling/trunk/contrib/scripting/sightly/engine/pom.xml
    sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerService.java

Modified: sling/trunk/contrib/scripting/sightly/engine/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/pom.xml?rev=1650895&r1=1650894&r2=1650895&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/pom.xml (original)
+++ sling/trunk/contrib/scripting/sightly/engine/pom.xml Sun Jan 11 12:11:41 2015
@@ -253,6 +253,32 @@
             <version>1.4</version>
             <scope>provided</scope>
         </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.11</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.9.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-mockito</artifactId>
+            <version>1.5.5</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>1.5.2</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>

Modified: sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerService.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerService.java?rev=1650895&r1=1650894&r2=1650895&view=diff
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerService.java (original)
+++ sling/trunk/contrib/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerService.java Sun Jan 11 12:11:41 2015
@@ -22,7 +22,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -142,19 +147,90 @@ public class SightlyJavaCompilerService
             }
         } else {
             try {
-                // the POJO was compiled but not cached by the unitChangeMonitor
+                // the POJO might have been compiled before from the repo but not cached by the unitChangeMonitor
                 return loadObject(className);
             } catch (CompilerException e) {
                 // the POJO was never compiled, nor cached by unitChangeMonitor
-                Resource pojoResource = resolver.getResource(pojoPath);
-                if (pojoResource != null) {
-                    return compileSource(pojoResource, className);
+                Set<String> possiblePaths = getPossiblePojoPaths(pojoPath);
+                Resource pojoResource;
+                for (String possiblePath : possiblePaths) {
+                    pojoResource = resolver.getResource(possiblePath);
+                    if (pojoResource != null) {
+                        return compileSource(pojoResource, className);
+                    }
                 }
                 throw new CompilerException(CompilerException.CompilerExceptionCause.MISSING_REPO_POJO);
             }
         }
     }
 
+    /**
+     * 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 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 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);
+                }
+            }
+        }
+    }
+
     private Object loadPOJOFromBundle(Resource resource, String className) {
         Resource resourceType = resource.getResourceResolver().getResource(resource.getResourceType());
         if (resourceType == null) {
@@ -239,7 +315,9 @@ public class SightlyJavaCompilerService
     }
 
     private String getPathFromJavaName(String className) {
-        return "/" + className.replaceAll("\\.", "/") + ".java";
+        String packageName = className.substring(0, className.lastIndexOf('.'));
+        String shortClassName = className.substring(packageName.length() + 1);
+        return "/" + packageName.replace(".", "/").replace("_", "-") + "/" + shortClassName + ".java";
     }
 
     private String createErrorMsg(List<CompilerMessage> errors) {
@@ -301,4 +379,23 @@ public class SightlyJavaCompilerService
         }
     }
 
+    /**
+     * 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('_');
+
+        private Character symbol;
+
+        private AmbiguousPathSymbol(Character symbol) {
+            this.symbol = symbol;
+        }
+
+        public Character getSymbol() {
+            return symbol;
+        }
+    }
+
 }

Added: sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java?rev=1650895&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java Sun Jan 11 12:11:41 2015
@@ -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.
+ ******************************************************************************/
+package org.apache.sling.scripting.sightly.impl.compiler;
+
+public class MockPojo {
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/MockPojo.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java?rev=1650895&view=auto
==============================================================================
--- sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java (added)
+++ sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java Sun Jan 11 12:11:41 2015
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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.compiler;
+
+import java.util.ArrayList;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.compiler.CompilationResult;
+import org.apache.sling.commons.compiler.CompilerMessage;
+import org.apache.sling.commons.compiler.Options;
+import org.apache.sling.jcr.compiler.JcrJavaCompiler;
+import org.apache.sling.scripting.sightly.impl.engine.UnitChangeMonitor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.powermock.reflect.Whitebox;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+public class SightlyJavaCompilerServiceTest {
+
+    private SightlyJavaCompilerService compiler;
+
+    @Before
+    public void setUp() throws Exception {
+        compiler = new SightlyJavaCompilerService();
+        UnitChangeMonitor ucm = new UnitChangeMonitor();
+        Whitebox.setInternalState(compiler, "unitChangeMonitor", ucm);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        compiler = null;
+    }
+
+    @Test
+    /**
+     * Tests that class names whose packages contain underscores are correctly expanded to JCR paths containing symbols that might be
+     * replaced with an underscores in order to obey Java naming conventions.
+     */
+    public void testGetInstanceForPojoFromRepoWithAmbigousPath() throws Exception {
+        String pojoPath = "/apps/my-project/test_components/a/Pojo.java";
+        String className = "apps.my_project.test_components.a.Pojo";
+        getInstancePojoTest(pojoPath, className);
+    }
+
+    @Test
+    /**
+     * Tests that class names whose package names don't contain underscores are correctly expanded to JCR paths.
+     */
+    public void testGetInstanceForPojoFromRepo() throws Exception {
+        String pojoPath = "/apps/myproject/testcomponents/a/Pojo.java";
+        String className = "apps.myproject.testcomponents.a.Pojo";
+        getInstancePojoTest(pojoPath, className);
+    }
+
+    private void getInstancePojoTest(String pojoPath, String className) throws Exception {
+        Resource pojoResource = Mockito.mock(Resource.class);
+        ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        when(pojoResource.getResourceResolver()).thenReturn(resolver);
+        when(resolver.getResource(pojoPath)).thenReturn(pojoResource);
+        JcrJavaCompiler jcrJavaCompiler = Mockito.mock(JcrJavaCompiler.class);
+        CompilationResult compilationResult = Mockito.mock(CompilationResult.class);
+        when(compilationResult.getErrors()).thenReturn(new ArrayList<CompilerMessage>());
+        when(jcrJavaCompiler.compile(Mockito.any(String[].class), Mockito.any(Options.class))).thenReturn(compilationResult);
+        when(compilationResult.loadCompiledClass(className)).thenAnswer(new Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocation) throws Throwable {
+                return MockPojo.class;
+            }
+        });
+        Whitebox.setInternalState(compiler, "jcrJavaCompiler", jcrJavaCompiler);
+        Object obj = compiler.getInstance(pojoResource, className);
+        assertTrue("Expected to obtain a " + MockPojo.class.getName() + " object.", obj instanceof MockPojo);
+    }
+}

Propchange: sling/trunk/contrib/scripting/sightly/engine/src/test/java/org/apache/sling/scripting/sightly/impl/compiler/SightlyJavaCompilerServiceTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain