This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.jcr.contentparser-1.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-contentparser.git
commit 081596f751b5ef0474978e02d2c7d42bc3f68eeb Author: Stefan Seifert <[email protected]> AuthorDate: Thu Mar 2 21:37:31 2017 +0000 SLING-6592 use DocViewProperty from vault-core to parse jcr xml property values fix artifactid git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/fscontentparser@1785194 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 29 ++-- .../impl/JcrXmlContentFileParser.java | 7 +- .../fscontentparser/impl/JcrXmlValueConverter.java | 192 +++++++++------------ .../impl/JcrXmlValueConverterTest.java | 59 ++++--- 4 files changed, 145 insertions(+), 142 deletions(-) diff --git a/pom.xml b/pom.xml index da20dc3..6b42222 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ <relativePath /> </parent> - <artifactId>org.apache.sling.fscontentparser</artifactId> + <artifactId>org.apache.sling.commons.fscontentparser</artifactId> <packaging>bundle</packaging> <version>1.0.0-SNAPSHOT</version> @@ -47,16 +47,6 @@ <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> - <configuration> - <instructions> - <!-- Embed the nessecary parts of the jackrabbit-jcr-commons bundle as described in http://njbartlett.name/2014/05/26/static-linking.html --> - <Conditional-Package>org.apache.jackrabbit.util</Conditional-Package> - <Import-Package> - !org.apache.jackrabbit.*, - * - </Import-Package> - </instructions> - </configuration> </plugin> <plugin> <groupId>org.apache.rat</groupId> @@ -100,12 +90,29 @@ <scope>compile</scope> </dependency> <dependency> + <groupId>javax.jcr</groupId> + <artifactId>jcr</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.jackrabbit</groupId> + <artifactId>jackrabbit-api</artifactId> + <version>2.8.0</version> + <scope>compile</scope> + </dependency> + <dependency> <groupId>org.apache.jackrabbit</groupId> <artifactId>jackrabbit-jcr-commons</artifactId> <version>2.8.0</version> <scope>compile</scope> </dependency> <dependency> + <groupId>org.apache.jackrabbit.vault</groupId> + <artifactId>org.apache.jackrabbit.vault</artifactId> + <version>3.1.18</version> + <scope>compile</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> diff --git a/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java b/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java index 060308e..c97317e 100644 --- a/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java +++ b/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java @@ -129,11 +129,10 @@ public final class JcrXmlContentFileParser implements ContentFileParser { for (int i=0; i<attributes.getLength(); i++) { String propertyName = helper.cleanupPropertyName(decodeName(attributes.getQName(i))); if (!helper.ignoreProperty(propertyName)) { - Object value = JcrXmlValueConverter.parseValue(attributes.getValue(i)); - if (value instanceof Object[]) { - value = helper.convertSingleTypeArray((Object[])value); + Object value = JcrXmlValueConverter.parseValue(propertyName, attributes.getValue(i)); + if (value != null) { + element.put(propertyName, value); } - element.put(propertyName, value); } } } diff --git a/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java b/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java index b3a817e..8e9fad4 100644 --- a/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java +++ b/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java @@ -18,23 +18,22 @@ */ package org.apache.sling.fscontentparser.impl; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.lang.reflect.Array; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Calendar; +import java.util.UUID; + +import javax.jcr.PropertyType; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.util.ISO8601; +import org.apache.jackrabbit.vault.util.DocViewProperty; /** * Parses JCR XML files that contains content fragments. */ class JcrXmlValueConverter { - private static final Pattern TYPE_PREFIX = Pattern.compile("^\\{([^\\{\\}]+)\\}(.+)$"); - private static final Pattern VALUE_ARRAY = Pattern.compile("^\\[(.*)\\]$"); - private JcrXmlValueConverter() { // static methods only } @@ -44,125 +43,106 @@ class JcrXmlValueConverter { * @param value XML attribute value * @return Value object */ - public static Object parseValue(final String rawValue) { - String value = rawValue; - String[] valueArray = null; - - if (rawValue == null) { + public static Object parseValue(final String name, final String value) { + if (value == null) { return null; } + DocViewProperty prop = DocViewProperty.parse(name, value); - // detect type prefix - String typePrefix = null; - Matcher typePrefixMatcher = TYPE_PREFIX.matcher(value); - if (typePrefixMatcher.matches()) { - typePrefix = typePrefixMatcher.group(1); - value = typePrefixMatcher.group(2); - } - - // check for array - Matcher arrayMatcher = VALUE_ARRAY.matcher(value); - if (arrayMatcher.matches()) { - value = null; - valueArray = splitPreserveAllTokens(arrayMatcher.group(1), ','); - } - // convert values - if (valueArray != null) { - Object[] result = new Object[valueArray.length]; - for (int i=0; i<valueArray.length; i++) { - result[i] = convertValue(valueArray[i], typePrefix, true); + if (prop.isMulti) { + Class<?> arrayType = getType(prop.type); + if (arrayType == null) { + return null; + } + Object result = Array.newInstance(arrayType, prop.values.length); + for (int i=0; i<prop.values.length; i++) { + Array.set(result, i, convertValue(prop.values[i], prop.type, true)); } return result; } else { - return convertValue(value, typePrefix, false); + return convertValue(prop.values[0], prop.type, false); } } /** - * Split string preserving all tokens - but ignore separators that are escaped with \. - * @param str Combined string - * @param sep Separator - * @return Tokens - */ - private static String[] splitPreserveAllTokens(String str, char sep) { - final int len = str.length(); - if (len == 0) { - return ArrayUtils.EMPTY_STRING_ARRAY; - } - final List<String> list = new ArrayList<String>(); - int i = 0, start = 0; - boolean match = false; - boolean lastMatch = false; - boolean escaped = false; - while (i < len) { - if (str.charAt(i) == '\\' && !escaped) { - escaped = true; - } - else { - if (str.charAt(i) == sep && !escaped) { - lastMatch = true; - list.add(str.substring(start, i)); - match = false; - start = ++i; - continue; - } - lastMatch = false; - match = true; - escaped = false; - } - i++; - } - if (match || lastMatch) { - list.add(str.substring(start, i)); - } - return list.toArray(new String[list.size()]); - } - - /** * Parse value depending on type prefix. * @param value Value - * @param typePrefix Type prefix + * @param type Type * @param inArray Value is in array * @return Value object */ - private static Object convertValue(final String value, final String typePrefix, final boolean inArray) { - if (typePrefix == null || StringUtils.equals(typePrefix, "Name")) { - return deescapeStringValue(value, inArray); - } - else if (StringUtils.equals(typePrefix, "Boolean")) { - return Boolean.valueOf(value); - } - else if (StringUtils.equals(typePrefix, "Long")) { - return Long.valueOf(value); - } - else if (StringUtils.equals(typePrefix, "Decimal")) { - return Double.valueOf(value); - } - else if (StringUtils.equals(typePrefix, "Date")) { - return ISO8601.parse(value); - } - else { - throw new IllegalArgumentException("Unexpected type prefix: " + typePrefix); + private static Object convertValue(final String value, final int type, final boolean inArray) { + switch (type) { + case PropertyType.UNDEFINED: + case PropertyType.STRING: + case PropertyType.NAME: + case PropertyType.PATH: + return value; + case PropertyType.BOOLEAN: + return Boolean.valueOf(value); + case PropertyType.LONG: + return Long.valueOf(value); + case PropertyType.DOUBLE: + case PropertyType.DECIMAL: + // TODO: specific handling for BigDecimal? not properly supported in ValueMapDecorator until very recent Sling API versions + return Double.valueOf(value); + case PropertyType.DATE: + return ISO8601.parse(value); + case PropertyType.REFERENCE: + case PropertyType.WEAKREFERENCE: + return UUID.fromString(value); + case PropertyType.URI: + try { + return new URI(value); + } + catch (URISyntaxException ex) { + throw new IllegalArgumentException("Unexpected URI syntax: " + value); + } + case PropertyType.BINARY: + // not supported - ignore value + return null; + default: + throw new IllegalArgumentException("Unexpected type: " + PropertyType.nameFromValue(type)); + } } /** - * De-escape string value. - * @param value Escaped string value - * @param inArray In array - * @return De-escaped string value + * Get java type for given JCR type. + * @param type Type + * @return Type */ - private static String deescapeStringValue(final String value, final boolean inArray) { - String descapedValue = value; - if (inArray) { - descapedValue = StringUtils.replace(descapedValue, "\\,", ","); + private static Class<?> getType(final int type) { + switch (type) { + case PropertyType.UNDEFINED: + case PropertyType.STRING: + case PropertyType.NAME: + case PropertyType.PATH: + return String.class; + case PropertyType.BOOLEAN: + return Boolean.class; + case PropertyType.LONG: + return Long.class; + case PropertyType.DOUBLE: + case PropertyType.DECIMAL: + // TODO: specific handling for BigDecimal? not properly supported in ValueMapDecorator until very recent Sling API versions + return Double.class; + case PropertyType.DATE: + return Calendar.class; + case PropertyType.REFERENCE: + case PropertyType.WEAKREFERENCE: + return UUID.class; + case PropertyType.URI: + return URI.class; + case PropertyType.BINARY: + // not supported - ignore value + return null; + default: + throw new IllegalArgumentException("Unexpected type: " + PropertyType.nameFromValue(type)); + } - else if (StringUtils.startsWith(descapedValue, "\\{") || StringUtils.startsWith(descapedValue, "\\[")) { - descapedValue = descapedValue.substring(1); - } - return StringUtils.replace(descapedValue, "\\\\", "\\"); } - + } diff --git a/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java b/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java index bddf053..2f02aae 100644 --- a/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java +++ b/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java @@ -23,75 +23,79 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import java.net.URI; import java.util.Calendar; +import java.util.UUID; import org.junit.Test; public class JcrXmlValueConverterTest { + + private static final String NAME = "prop1"; @Test public void testNull() { - assertNull(parseValue(null)); + assertNull(parseValue(NAME, null)); } @Test(expected = IllegalArgumentException.class) public void testInvalid() { - parseValue("{InvalidType}xyz"); + parseValue(NAME, "{InvalidType}xyz"); } @Test public void testString() { - assertEquals("myString", parseValue("myString")); - assertEquals("prop", "myString [ ] { } \\ ,", parseValue("myString [ ] { } \\\\ ,")); - assertEquals("{myString}", parseValue("\\{myString}")); - assertEquals("aaa{myString}", parseValue("aaa{myString}")); - assertEquals("[myString]", parseValue("\\[myString]")); - assertEquals("aaa[myString]", parseValue("aaa[myString]")); + assertEquals("myString", parseValue(NAME, "myString")); + assertEquals("prop", "myString [ ] { } \\ ,", parseValue(NAME, "myString [ ] { } \\\\ ,")); + assertEquals("{myString}", parseValue(NAME, "\\{myString}")); + assertEquals("aaa{myString}", parseValue(NAME, "aaa{myString}")); + assertEquals("[myString]", parseValue(NAME, "\\[myString]")); + assertEquals("aaa[myString]", parseValue(NAME, "aaa[myString]")); } @Test public void testStringArray() { - assertArrayEquals(new Object[] { "myString1", "myString2" }, (Object[]) parseValue("[myString1,myString2]")); + assertArrayEquals(new Object[] { "myString1", "myString2" }, (Object[]) parseValue(NAME, "[myString1,myString2]")); assertArrayEquals(new Object[] { "myString1,[]\\äöü߀", "myString2", "myString3 [ ] { } \\ ,", "", "[myString5]", "{myString6}" }, - (Object[]) parseValue("[myString1\\,[]\\\\äöü߀,myString2,myString3 [ ] { } \\\\ \\,,,[myString5],{myString6}]")); + (Object[]) parseValue(NAME, "[myString1\\,[]\\\\äöü߀,myString2,myString3 [ ] { } \\\\ \\,,,[myString5],{myString6}]")); } @Test public void testBoolean() { - assertEquals(true, parseValue("{Boolean}true")); - assertEquals(false, parseValue("{Boolean}false")); + assertEquals(true, parseValue(NAME, "{Boolean}true")); + assertEquals(false, parseValue(NAME, "{Boolean}false")); } @Test public void testBooleanArray() { - assertArrayEquals(new Object[] { true, false }, (Object[]) parseValue("{Boolean}[true,false]")); + assertArrayEquals(new Object[] { true, false }, (Object[]) parseValue(NAME, "{Boolean}[true,false]")); } @Test public void testLong() { - assertEquals(1L, parseValue("{Long}1")); - assertEquals(10000000000L, parseValue("{Long}10000000000")); + assertEquals(1L, parseValue(NAME, "{Long}1")); + assertEquals(10000000000L, parseValue(NAME, "{Long}10000000000")); } @Test public void testLongArray() { - assertArrayEquals(new Object[] { 1L, 2L }, (Object[]) parseValue("{Long}[1,2]")); - assertArrayEquals(new Object[] { 10000000000L, 20000000000L }, (Object[]) parseValue("{Long}[10000000000,20000000000]")); + assertArrayEquals(new Object[] { 1L, 2L }, (Object[]) parseValue(NAME, "{Long}[1,2]")); + assertArrayEquals(new Object[] { 10000000000L, 20000000000L }, (Object[]) parseValue(NAME, "{Long}[10000000000,20000000000]")); } @Test public void testDouble() { - assertEquals(1.234d, parseValue("{Decimal}1.234")); + assertEquals(1.234d, parseValue(NAME, "{Decimal}1.234")); } @Test public void testDoubleArray() { - assertArrayEquals(new Object[] { 1.234d, 2.345d }, (Object[]) parseValue("{Decimal}[1.234,2.345]")); + assertArrayEquals(new Object[] { 1.234d, 2.345d }, (Object[]) parseValue(NAME, "{Decimal}[1.234,2.345]")); } @Test public void testCalendar() { - Calendar value = (Calendar)parseValue("{Date}2010-09-05T15:10:20.000Z"); + Calendar value = (Calendar)parseValue(NAME, "{Date}2010-09-05T15:10:20.000Z"); assertEquals(2010, value.get(Calendar.YEAR)); assertEquals(8, value.get(Calendar.MONTH)); assertEquals(5, value.get(Calendar.DAY_OF_MONTH)); @@ -99,7 +103,20 @@ public class JcrXmlValueConverterTest { @Test public void testStringArrayRepPrivileges() { - assertArrayEquals(new Object[] { "rep:write", "crx:replicate", "jcr:read" }, (Object[]) parseValue("{Name}[rep:write,crx:replicate,jcr:read]")); + assertArrayEquals(new Object[] { "rep:write", "crx:replicate", "jcr:read" }, (Object[]) parseValue(NAME, "{Name}[rep:write,crx:replicate,jcr:read]")); + } + + @Test + public void testReference() { + UUID uuid = UUID.randomUUID(); + UUID value = (UUID)parseValue(NAME, "{Reference}" + uuid.toString()); + assertEquals(uuid, value); + } + + @Test + public void testURI() { + URI value = (URI)parseValue(NAME, "{URI}http://www.jodelkaiser.de/"); + assertEquals("http://www.jodelkaiser.de/", value.toString()); } } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
