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('_');