You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2017/03/02 17:17:18 UTC

svn commit: r1785165 [1/2] - in /sling/trunk: ./ bundles/commons/fscontentparser/ bundles/commons/fscontentparser/src/ bundles/commons/fscontentparser/src/main/ bundles/commons/fscontentparser/src/main/java/ bundles/commons/fscontentparser/src/main/jav...

Author: sseifert
Date: Thu Mar  2 17:17:18 2017
New Revision: 1785165

URL: http://svn.apache.org/viewvc?rev=1785165&view=rev
Log:
SLING-6592 File System Content File Parser

Added:
    sling/trunk/bundles/commons/fscontentparser/
    sling/trunk/bundles/commons/fscontentparser/pom.xml   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/
    sling/trunk/bundles/commons/fscontentparser/src/main/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/TestUtils.java   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/content-test/
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/content-test/content.jcr.xml   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/content-test/content.json   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/invalid-test/
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/invalid-test/contentWithObjectList.json   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/invalid-test/invalid.jcr.xml   (with props)
    sling/trunk/bundles/commons/fscontentparser/src/test/resources/invalid-test/invalid.json   (with props)
Modified:
    sling/trunk/pom.xml

Added: sling/trunk/bundles/commons/fscontentparser/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/pom.xml?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/pom.xml (added)
+++ sling/trunk/bundles/commons/fscontentparser/pom.xml Thu Mar  2 17:17:18 2017
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>30-SNAPSHOT</version>
+        <relativePath />
+    </parent>
+
+    <artifactId>org.apache.sling.fscontentparser</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <name>Apache Sling File System Content File Parser</name>
+    <description>
+        Parser for repository content stored in files (e.g. JSON, JCR XML).
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/commons/fscontentparser</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/commons/fscontentparser</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <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>
+                <artifactId>apache-rat-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                      <exclude>src/test/resources/content-test/**</exclude>
+                      <exclude>src/test/resources/invalid-test/**</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.johnzon</groupId>
+            <artifactId>johnzon-core</artifactId>
+            <version>1.0.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-json_1.0_spec</artifactId>
+            <version>1.0-alpha-1</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>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>15.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

Propchange: sling/trunk/bundles/commons/fscontentparser/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/pom.xml
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java Thu Mar  2 17:17:18 2017
@@ -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.fscontentparser;
+
+/**
+ * Content file types.
+ */
+public final class ContentFileExtension {
+    
+    /**
+     * JSON content files.
+     */
+    public static final String JSON = "json";
+
+    /**
+     * JCR XML content files.
+     */
+    public static final String JCR_XML = "jcr.xml";
+        
+    private ContentFileExtension() {
+        // constants only
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileExtension.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,50 @@
+/*
+ * 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.fscontentparser;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Parses repository content from a file.
+ * Implementations have to be thread-safe.
+ */
+public interface ContentFileParser {
+
+    /**
+     * Parse content file.
+     * @param file File
+     * @return Content
+     * @throws IOException When I/O error occurs.
+     * @throws ParseException When parsing error occurs.
+     */
+    Map<String,Object> parse(File file) throws IOException, ParseException;
+    
+    /**
+     * Parse content file.
+     * @param file File
+     * @return Content
+     * @throws IOException When I/O error occurs.
+     * @throws ParseException When parsing error occurs.
+     */
+    Map<String,Object> parse(InputStream is) throws IOException, ParseException;
+
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,59 @@
+/*
+ * 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.fscontentparser;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.fscontentparser.impl.JcrXmlContentFileParser;
+import org.apache.sling.fscontentparser.impl.JsonContentFileParser;
+
+/**
+ * Factory for content file parsers.
+ */
+public final class ContentFileParserFactory {
+
+    private ContentFileParserFactory() {
+        // static methods only
+    }
+    
+    /**
+     * Create content file parser.
+     * @param fileExtension File extension from {@link ContentFileExtension}.
+     * @return Content file parser
+     */
+    public static ContentFileParser create(String fileExtension) {
+        return create(fileExtension, new ParserOptions());
+    }
+    
+    /**
+     * Create content file parser.
+     * @param fileExtension File extension from {@link ContentFileExtension}.
+     * @param options Parser options
+     * @return Content file parser
+     */
+    public static ContentFileParser create(String fileExtension, ParserOptions options) {
+        if (StringUtils.equals(fileExtension, ContentFileExtension.JSON)) {
+            return new JsonContentFileParser(options);
+        }
+        else if (StringUtils.equals(fileExtension, ContentFileExtension.JCR_XML)) {
+            return new JcrXmlContentFileParser(options);
+        }
+        throw new IllegalArgumentException("Unsupported file extension: " + fileExtension);
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ContentFileParserFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,42 @@
+/*
+ * 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.fscontentparser;
+
+/**
+ * Parsing exception.
+ */
+public final class ParseException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @param message Message
+     */
+    public ParseException(String message) {
+        super(message);
+    }
+    
+    /**
+     * @param message Message
+     * @param cause Cause
+     */
+    public ParseException(String message, Throwable cause) {
+        super(message, cause);
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParseException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,116 @@
+/*
+ * 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.fscontentparser;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Options for content filer parser.
+ */
+public final class ParserOptions {
+    
+    /**
+     * Default primary type.
+     */
+    public static final String DEFAULT_PRIMARY_TYPE = "nt:unstructured";
+
+    /**
+     * Default list of prefixes to remove from property names.
+     */
+    public static final Set<String> DEFAULT_REMOVE_PROPERTY_NAME_PREFIXES
+            = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("jcr:reference:", "jcr:path:")));
+    
+    private String defaultPrimaryType = DEFAULT_PRIMARY_TYPE;
+    private boolean detectCalendarValues;
+    private Set<String> ignorePropertyNames;
+    private Set<String> ignoreResourceNames;
+    private Set<String> removePropertyNamePrefixes = DEFAULT_REMOVE_PROPERTY_NAME_PREFIXES;
+    
+    /**
+     * Default "jcr:primaryType" property for resources that have no explicit value for this value.
+     * If set to null, not default type is applied.
+     * @param value Default primary type.
+     * @return this
+     */
+    public ParserOptions defaultPrimaryType(String value) {
+        this.defaultPrimaryType = value;
+        return this;
+    }
+    public String getDefaultPrimaryType() {
+        return defaultPrimaryType;
+    }
+
+    /**
+     * Some content file formats like JSON do not contain information to identify date/time values.
+     * Instead they have to be detected by heuristics by trying to parse every string value.
+     * This mode is disabled by default.
+     * @param value Activate calendar value detection
+     * @return this
+     */
+    public ParserOptions detectCalendarValues(boolean value) {
+        this.detectCalendarValues = value;
+        return this;
+    }
+    public boolean isDetectCalendarValues() {
+        return detectCalendarValues;
+    }
+
+    /**
+     * Set a list of property names that should be ignored when parsing the content file.
+     * @param value List of property names 
+     * @return this
+     */
+    public ParserOptions ignorePropertyNames(Set<String> value) {
+        this.ignorePropertyNames = value;
+        return this;
+    }
+    public Set<String> getIgnorePropertyNames() {
+        return ignorePropertyNames;
+    }
+
+    /**
+     * Set a list of resource/node names that should be ignored when parsing the content file.
+     * @param value List of resource/node names
+     * @return this
+     */
+    public ParserOptions ignoreResourceNames(Set<String> value) {
+        this.ignoreResourceNames = value;
+        return this;
+    }
+    public Set<String> getIgnoreResourceNames() {
+        return ignoreResourceNames;
+    }
+
+    /**
+     * Set a list of property name prefixes that should be removed automatically from the property name. 
+     * @param value List of property name prefixes
+     * @return this
+     */
+    public ParserOptions removePropertyNamePrefixes(Set<String> value) {
+        this.removePropertyNamePrefixes = value;
+        return this;
+    }
+    public Set<String> getRemovePropertyNamePrefixes() {
+        return removePropertyNamePrefixes;
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/ParserOptions.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,159 @@
+/*
+ * 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.fscontentparser.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.sling.fscontentparser.ContentFileParser;
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Parses JCR XML files that contains content fragments.
+ * Instance of this class is thread-safe.
+ */
+public final class JcrXmlContentFileParser implements ContentFileParser {
+    
+    private final ParserHelper helper;    
+    private final SAXParserFactory saxParserFactory;
+    
+    public JcrXmlContentFileParser(ParserOptions options) {
+        this.helper = new ParserHelper(options);
+        saxParserFactory = SAXParserFactory.newInstance();
+        saxParserFactory.setNamespaceAware(true);
+    }
+    
+    @Override
+    public Map<String,Object> parse(File file) throws IOException, ParseException {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return parse(fis);
+        }
+    }
+    
+    @Override
+    public Map<String,Object> parse(InputStream is) throws IOException, ParseException {
+        try {
+            XmlHandler xmlHandler = new XmlHandler();
+            SAXParser parser = saxParserFactory.newSAXParser();
+            parser.parse(is, xmlHandler);
+            if (xmlHandler.hasError()) {
+                throw xmlHandler.getError();
+            }
+            return xmlHandler.getContent();
+        }
+        catch (ParserConfigurationException | SAXException ex) {
+            throw new ParseException("Error parsing JCR XML content.", ex);
+        }
+    }
+    
+    /**
+     * Decodes element or attribute names.
+     * @param qname qname
+     * @return Decoded name
+     */
+    static String decodeName(String qname) {
+        return ISO9075.decode(qname);
+    }
+    
+    /**
+     * Parses XML stream to Map.
+     */
+    class XmlHandler extends DefaultHandler {
+        private final Map<String,Object> content = new LinkedHashMap<>();
+        private final Stack<Map<String,Object>> elements = new Stack<>();
+        private SAXParseException error;
+        
+        public Map<String,Object> getContent() {
+            return content;
+        }
+        
+        public boolean hasError() {
+            return error != null;
+        }
+        
+        public SAXParseException getError() {
+            return error;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attributes)
+                throws SAXException {
+            
+            // prepare map for element
+            Map<String,Object> element;
+            if (elements.isEmpty()) {
+                element = content;
+            }
+            else {
+                element = new HashMap<>();
+                String resourceName = decodeName(qName);
+                if (!helper.ignoreResource(resourceName)) {
+                    elements.peek().put(resourceName, element);
+                }
+            }
+            elements.push(element);
+            
+            // get attributes
+            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);
+                    }
+                    element.put(propertyName, value);
+                }
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            Map<String,Object> element = elements.pop();
+            helper.ensureDefaultPrimaryType(element);
+        }
+
+        @Override
+        public void error(SAXParseException ex) throws SAXException {
+            this.error = ex;
+        }
+
+        @Override
+        public void fatalError(SAXParseException ex) throws SAXException {
+            this.error = ex;
+        }
+        
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,168 @@
+/*
+ * 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.fscontentparser.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.util.ISO8601;
+
+/**
+ * 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
+    }
+    
+    /**
+     * Parse JSON value from XML Attribute.
+     * @param value XML attribute value
+     * @return Value object
+     */
+    public static Object parseValue(final String rawValue) {
+        String value = rawValue;
+        String[] valueArray = null;
+        
+        if (rawValue == null) {
+            return null;
+        }
+        
+        // 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);
+            }
+            return result;
+        }
+        else {
+            return convertValue(value, typePrefix, 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 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);
+        }
+    }
+    
+    /**
+     * De-escape string value.
+     * @param value Escaped string value
+     * @param inArray In array
+     * @return De-escaped string value
+     */
+    private static String deescapeStringValue(final String value, final boolean inArray) {
+        String descapedValue = value;
+        if (inArray) {
+          descapedValue = StringUtils.replace(descapedValue, "\\,", ",");
+        }
+        else if (StringUtils.startsWith(descapedValue, "\\{") || StringUtils.startsWith(descapedValue, "\\[")) {
+            descapedValue = descapedValue.substring(1);
+        }
+        return StringUtils.replace(descapedValue, "\\\\", "\\");
+    }
+        
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,138 @@
+/*
+ * 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.fscontentparser.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParsingException;
+
+import org.apache.sling.fscontentparser.ContentFileParser;
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+
+/**
+ * Parses JSON files that contains content fragments.
+ * Instance of this class is thread-safe.
+ */
+public final class JsonContentFileParser implements ContentFileParser {
+    
+    private final ParserHelper helper;    
+    private final JsonReaderFactory jsonReaderFactory;
+    
+    public JsonContentFileParser(ParserOptions options) {
+        this.helper = new ParserHelper(options);
+        // allow comments in JSON files
+        Map<String,Object> jsonReaderFactoryConfig = new HashMap<>();
+        jsonReaderFactoryConfig.put("org.apache.johnzon.supports-comments", true);
+        jsonReaderFactory = Json.createReaderFactory(jsonReaderFactoryConfig);
+    }
+    
+    @Override
+    public Map<String,Object> parse(File file) throws IOException, ParseException {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return parse(fis);
+        }
+    }
+    
+    @Override
+    public Map<String,Object> parse(InputStream is) throws IOException, ParseException {
+        try (JsonReader reader = jsonReaderFactory.createReader(is)) {
+            return toMap(reader.readObject());
+        }
+        catch (JsonParsingException ex) {
+            throw new ParseException("Error parsing JSON content.", ex);
+        }
+    }
+    
+    private Map<String,Object> toMap(JsonObject object) {
+        Map<String,Object> map = new LinkedHashMap<>();
+        for (Map.Entry<String, JsonValue> entry : object.entrySet()) {
+            String childName = entry.getKey();
+            Object value = convertValue(entry.getValue());
+            boolean ignore = false;
+            if (value instanceof Map) {
+                ignore = helper.ignoreResource(childName);
+            }
+            else {
+                childName = helper.cleanupPropertyName(childName);
+                ignore = helper.ignoreProperty(childName);
+            }
+            if (!ignore) {
+                map.put(childName, value);
+            }
+        }
+        helper.ensureDefaultPrimaryType(map);
+        return map;
+    }
+    
+    private Object convertValue(JsonValue value) {
+        switch (value.getValueType()) {
+            case STRING:
+                String stringValue = ((JsonString)value).getString();
+                Calendar calendarValue = helper.tryParseCalendar(stringValue);
+                if (calendarValue != null) {
+                    return calendarValue;
+                }
+                else {
+                    return stringValue;
+                }
+            case NUMBER:
+                JsonNumber numberValue = (JsonNumber)value;
+                if (numberValue.isIntegral()) {
+                    return numberValue.longValue();
+                }
+                else {
+                    return numberValue.doubleValue();
+                }
+            case TRUE:
+                return true;
+            case FALSE:
+                return false;
+            case NULL:
+                return null;
+            case ARRAY:
+                JsonArray arrayValue = (JsonArray)value;
+                Object[] values = new Object[arrayValue.size()];
+                for (int i=0; i<values.length; i++) {
+                    values[i] = convertValue(arrayValue.get(i));
+                }
+                return helper.convertSingleTypeArray(values);
+            case OBJECT:
+                return toMap((JsonObject)value);
+            default:
+                throw new ParseException("Unexpected JSON value type: " + value.getValueType());
+        }
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/JsonContentFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,134 @@
+/*
+ * 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.fscontentparser.impl;
+
+import java.lang.reflect.Array;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+
+/**
+ * Helper parsing logic based on parser options.
+ */
+class ParserHelper {
+
+    static final String JCR_PRIMARYTYPE = "jcr:primaryType";
+
+    static final String ECMA_DATE_FORMAT = "EEE MMM dd yyyy HH:mm:ss 'GMT'Z";
+    static final Locale DATE_FORMAT_LOCALE = Locale.US;
+
+    private final ParserOptions options;
+    private final DateFormat calendarFormat;
+
+    public ParserHelper(ParserOptions options) {
+        this.options = options;
+        if (options.isDetectCalendarValues()) {
+            this.calendarFormat = new SimpleDateFormat(ECMA_DATE_FORMAT, DATE_FORMAT_LOCALE);
+        }
+        else {
+            this.calendarFormat = null;
+        }
+    }
+
+    public void ensureDefaultPrimaryType(Map<String, Object> map) {
+        String defaultPrimaryType = options.getDefaultPrimaryType();
+        if (defaultPrimaryType != null) {
+            if (!map.containsKey(JCR_PRIMARYTYPE)) {
+                map.put(JCR_PRIMARYTYPE, defaultPrimaryType);
+            }
+        }
+    }
+
+    public Calendar tryParseCalendar(String value) {
+        if (options.isDetectCalendarValues() && !StringUtils.isBlank(value)) {
+            synchronized (calendarFormat) {
+                try {
+                    Date date = calendarFormat.parse(value);
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(date);
+                    return calendar;
+                }
+                catch (java.text.ParseException ex) {
+                    // ignore
+                }
+            }
+        }
+        return null;
+    }
+    
+    public boolean ignoreProperty(String propertyName) {
+        return ignoreNames(options.getIgnorePropertyNames(), propertyName);
+    }
+    
+    public boolean ignoreResource(String resourceName) {
+        return ignoreNames(options.getIgnoreResourceNames(), resourceName);
+    }
+    
+    private boolean ignoreNames(Set<String> names, String name) {
+        return names != null && names.contains(name);
+    }
+
+    public String cleanupPropertyName(String propertyName) {
+        Set<String> prefixes = options.getRemovePropertyNamePrefixes();
+        if (prefixes != null) {
+            for (String prefix : prefixes) {
+                if (StringUtils.startsWith(propertyName, prefix)) {
+                    return StringUtils.substringAfter(propertyName, prefix);
+                  }
+            }
+        }
+        return propertyName;
+    }
+    
+    public Object convertSingleTypeArray(Object[] values) {
+        if (values.length == 0) {
+            return values;
+        }
+        Class<?> itemType = null;
+        for (Object value : values) {
+            if (value == null) {
+                throw new ParseException("Multivalue array must not contain null values.");
+            }
+            if (value instanceof Map) {
+                throw new ParseException("Multivalue array must not contain maps/objects.");
+            }
+            if (itemType == null) {
+                itemType = value.getClass();
+            }
+            else if (itemType != value.getClass()) {
+                throw new ParseException("Multivalue array must not contain values with different types "
+                        + "(" + itemType.getName() + ", " + value.getClass().getName() + ").");
+            }
+        }
+        Object convertedArray = Array.newInstance(itemType, values.length);
+        for (int i=0; i<values.length; i++) {
+            Array.set(convertedArray, i, values[i]);
+        }
+        return convertedArray;
+    }
+    
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/impl/ParserHelper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/**
+ * Parser for repository content stored in files (e.g. JSON, JCR XML).
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.sling.fscontentparser;

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/main/java/org/apache/sling/fscontentparser/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,117 @@
+/*
+ * 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.fscontentparser.impl;
+
+import static org.apache.sling.fscontentparser.impl.TestUtils.getDeep;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.sling.fscontentparser.ContentFileExtension;
+import org.apache.sling.fscontentparser.ContentFileParser;
+import org.apache.sling.fscontentparser.ContentFileParserFactory;
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class JcrXmlContentFileParserTest {
+
+    private File file;
+
+    @Before
+    public void setUp() throws Exception {
+        file = new File("src/test/resources/content-test/content.jcr.xml");
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testParseJcrXml() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JCR_XML);
+        Map<String,Object> content = underTest.parse(file);
+        assertNotNull(content);
+        assertEquals("app:Page", content.get("jcr:primaryType"));
+        assertEquals("app:PageContent", ((Map<String,Object>)content.get("jcr:content")).get("jcr:primaryType"));
+    }
+
+    @Test(expected=ParseException.class)
+    public void testParseInvalidJcrXml() throws Exception {
+        file = new File("src/test/resources/invalid-test/invalid.jcr.xml");
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JCR_XML);
+        underTest.parse(file);
+    }
+
+    @Test
+    public void testDataTypes() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JCR_XML);
+        Map<String,Object> content = underTest.parse(file);
+        Map<String,Object> props = getDeep(content, "jcr:content");
+        
+        assertEquals("en", props.get("jcr:title"));
+        assertEquals(true, props.get("includeAside"));
+        assertEquals((Long)1234567890123L, props.get("longProp"));
+        assertEquals((Double)1.2345d, (Double)props.get("decimalProp"), 0.00001d);
+        
+        assertArrayEquals(new String[] { "aa", "bb", "cc" }, (String[])props.get("stringPropMulti"));
+        assertArrayEquals(new Long[] { 1234567890123L, 55L }, (Long[])props.get("longPropMulti"));
+        
+        Calendar calendar = (Calendar)props.get("dateProp");
+        calendar.setTimeZone(TimeZone.getTimeZone("GMT+2"));
+        assertEquals(2014, calendar.get(Calendar.YEAR));
+        assertEquals(9, calendar.get(Calendar.MONTH) + 1);
+        assertEquals(19, calendar.get(Calendar.DAY_OF_MONTH));
+        assertEquals(21, calendar.get(Calendar.HOUR_OF_DAY));
+        assertEquals(20, calendar.get(Calendar.MINUTE));
+        assertEquals(26, calendar.get(Calendar.SECOND));
+        assertEquals(812, calendar.get(Calendar.MILLISECOND));
+    }
+
+    @Test
+    public void testDecodeName() {
+        assertEquals("jcr:title", JcrXmlContentFileParser.decodeName("jcr:" + ISO9075.encode("title")));
+        assertEquals("sling:123", JcrXmlContentFileParser.decodeName("sling:" + ISO9075.encode("123")));
+    }
+
+    @Test
+    public void testIgnoreResourcesProperties() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JCR_XML, new ParserOptions()
+                .ignoreResourceNames(ImmutableSet.of("teaserbar", "aside"))
+                .ignorePropertyNames(ImmutableSet.of("longProp", "jcr:title")));
+        Map<String,Object> content = underTest.parse(file);
+        Map<String,Object> props = getDeep(content, "jcr:content");
+        
+        assertEquals("HOME", props.get("navTitle"));
+        assertNull(props.get("jcr:title"));
+        assertNull(props.get("longProp"));
+        
+        assertNull(props.get("teaserbar"));
+        assertNull(props.get("aside"));
+        assertNotNull(props.get("content"));
+    }
+
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlContentFileParserTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,105 @@
+/*
+ * 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.fscontentparser.impl;
+
+import static org.apache.sling.fscontentparser.impl.JcrXmlValueConverter.parseValue;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Calendar;
+
+import org.junit.Test;
+
+public class JcrXmlValueConverterTest {
+
+    @Test
+    public void testNull() {
+        assertNull(parseValue(null));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalid() {
+        parseValue("{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]"));
+    }
+
+    @Test
+    public void testStringArray() {
+        assertArrayEquals(new Object[] { "myString1", "myString2" }, (Object[]) parseValue("[myString1,myString2]"));
+        assertArrayEquals(new Object[] { "myString1,[]\\äöü߀", "myString2", "myString3 [ ] { } \\ ,", "", "[myString5]", "{myString6}" },
+                (Object[]) parseValue("[myString1\\,[]\\\\äöü߀,myString2,myString3 [ ] { } \\\\ \\,,,[myString5],{myString6}]"));
+    }
+
+    @Test
+    public void testBoolean() {
+        assertEquals(true, parseValue("{Boolean}true"));
+        assertEquals(false, parseValue("{Boolean}false"));
+    }
+
+    @Test
+    public void testBooleanArray() {
+        assertArrayEquals(new Object[] { true, false }, (Object[]) parseValue("{Boolean}[true,false]"));
+    }
+
+    @Test
+    public void testLong() {
+        assertEquals(1L, parseValue("{Long}1"));
+        assertEquals(10000000000L, parseValue("{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]"));
+    }
+
+    @Test
+    public void testDouble() {
+        assertEquals(1.234d, parseValue("{Decimal}1.234"));
+    }
+
+    @Test
+    public void testDoubleArray() {
+        assertArrayEquals(new Object[] { 1.234d, 2.345d }, (Object[]) parseValue("{Decimal}[1.234,2.345]"));
+    }
+
+    @Test
+    public void testCalendar() {
+        Calendar value = (Calendar)parseValue("{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));
+    }
+
+    @Test
+    public void testStringArrayRepPrivileges() {
+        assertArrayEquals(new Object[] { "rep:write", "crx:replicate", "jcr:read" }, (Object[]) parseValue("{Name}[rep:write,crx:replicate,jcr:read]"));
+    }
+
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JcrXmlValueConverterTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,152 @@
+/*
+ * 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.fscontentparser.impl;
+
+import static org.apache.sling.fscontentparser.impl.TestUtils.getDeep;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.util.Calendar;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.sling.fscontentparser.ContentFileExtension;
+import org.apache.sling.fscontentparser.ContentFileParser;
+import org.apache.sling.fscontentparser.ContentFileParserFactory;
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class JsonContentFileParserTest {
+
+    private File file;
+
+    @Before
+    public void setUp() {
+        file = new File("src/test/resources/content-test/content.json");
+    }
+
+    @Test
+    public void testPageJcrPrimaryType() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+
+        assertEquals("app:Page", content.get("jcr:primaryType"));
+    }
+
+    @Test
+    public void testDataTypes() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+
+        Map<String, Object> props = getDeep(content, "toolbar/profiles/jcr:content");
+        assertEquals(true, props.get("hideInNav"));
+
+        assertEquals(1234567890123L, props.get("longProp"));
+        assertEquals(1.2345d, (Double) props.get("decimalProp"), 0.00001d);
+        assertEquals(true, props.get("booleanProp"));
+
+        assertArrayEquals(new Long[] { 1234567890123L, 55L }, (Long[]) props.get("longPropMulti"));
+        assertArrayEquals(new Double[] { 1.2345d, 1.1d }, (Double[]) props.get("decimalPropMulti"));
+        assertArrayEquals(new Boolean[] { true, false }, (Boolean[]) props.get("booleanPropMulti"));
+    }
+
+    @Test
+    public void testContentProperties() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+
+        Map<String, Object> props = getDeep(content, "jcr:content/header");
+        assertEquals("/content/dam/sample/header.png", props.get("imageReference"));
+    }
+
+    @Test
+    public void testCalendar() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON,
+                new ParserOptions().detectCalendarValues(true));
+        Map<String, Object> content = underTest.parse(file);
+
+        Map<String, Object> props = getDeep(content, "jcr:content");
+
+        Calendar calendar = (Calendar) props.get("app:lastModified");
+        assertNotNull(calendar);
+
+        calendar.setTimeZone(TimeZone.getTimeZone("GMT+2"));
+
+        assertEquals(2014, calendar.get(Calendar.YEAR));
+        assertEquals(4, calendar.get(Calendar.MONTH) + 1);
+        assertEquals(22, calendar.get(Calendar.DAY_OF_MONTH));
+
+        assertEquals(15, calendar.get(Calendar.HOUR_OF_DAY));
+        assertEquals(11, calendar.get(Calendar.MINUTE));
+        assertEquals(24, calendar.get(Calendar.SECOND));
+    }
+
+    @Test
+    public void testUTF8Chars() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+
+        Map<String, Object> props = getDeep(content, "jcr:content");
+
+        assertEquals("äöü߀", props.get("utf8Property"));
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseInvalidJson() throws Exception {
+        file = new File("src/test/resources/invalid-test/invalid.json");
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+        assertNull(content);
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseInvalidJsonWithObjectList() throws Exception {
+        file = new File("src/test/resources/invalid-test/contentWithObjectList.json");
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON);
+        Map<String, Object> content = underTest.parse(file);
+        assertNull(content);
+    }
+
+    @Test
+    public void testIgnoreResourcesProperties() throws Exception {
+        ContentFileParser underTest = ContentFileParserFactory.create(ContentFileExtension.JSON,
+                new ParserOptions().ignoreResourceNames(ImmutableSet.of("header", "newslist"))
+                        .ignorePropertyNames(ImmutableSet.of("jcr:title")));
+        Map<String, Object> content = underTest.parse(file);
+        Map<String, Object> props = getDeep(content, "jcr:content");
+
+        assertEquals("Sample Homepage", props.get("pageTitle"));
+        assertNull(props.get("jcr:title"));
+
+        assertNull(props.get("header"));
+        assertNull(props.get("newslist"));
+        assertNotNull(props.get("lead"));
+
+        assertEquals("abc", props.get("refpro1"));
+        assertEquals("def", props.get("pathprop1"));
+    }
+
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/JsonContentFileParserTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java?rev=1785165&view=auto
==============================================================================
--- sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java (added)
+++ sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java Thu Mar  2 17:17:18 2017
@@ -0,0 +1,199 @@
+/*
+ * 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.fscontentparser.impl;
+
+import static org.apache.sling.fscontentparser.ParserOptions.DEFAULT_PRIMARY_TYPE;
+import static org.apache.sling.fscontentparser.impl.ParserHelper.JCR_PRIMARYTYPE;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.sling.fscontentparser.ParseException;
+import org.apache.sling.fscontentparser.ParserOptions;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class ParserHelperTest {
+
+    @Test
+    public void testEnsureDefaultPrimaryType() {
+        Map<String,Object> content = new HashMap<>();
+        content.put("prop1", "value1");
+
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        underTest.ensureDefaultPrimaryType(content);
+        
+        assertEquals(ImmutableMap.<String,Object>of("prop1", "value1", JCR_PRIMARYTYPE, DEFAULT_PRIMARY_TYPE), content);
+    }
+
+    @Test
+    public void testEnsureDefaultPrimaryType_Disabled() {
+        Map<String,Object> content = new HashMap<>();
+        content.put("prop1", "value1");
+
+        ParserHelper underTest = new ParserHelper(new ParserOptions().defaultPrimaryType(null));
+        underTest.ensureDefaultPrimaryType(content);
+        
+        assertEquals(ImmutableMap.<String,Object>of("prop1", "value1"), content);
+    }
+
+    @Test
+    public void testEnsureDefaultPrimaryType_AlreadySet() {
+        Map<String,Object> content = new HashMap<>();
+        content.put("prop1", "value1");
+        content.put(JCR_PRIMARYTYPE, "type1");
+
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        underTest.ensureDefaultPrimaryType(content);
+        
+        assertEquals(ImmutableMap.<String,Object>of("prop1", "value1", JCR_PRIMARYTYPE, "type1"), content);
+    }
+
+    @Test
+    public void testTryParseCalendar() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions().detectCalendarValues(true));
+        
+        Calendar value = underTest.tryParseCalendar("Tue Apr 22 2014 15:11:24 GMT+0200");
+        assertNotNull(value);
+
+        value.setTimeZone(TimeZone.getTimeZone("GMT+2"));
+
+        assertEquals(2014, value.get(Calendar.YEAR));
+        assertEquals(4, value.get(Calendar.MONTH) + 1);
+        assertEquals(22, value.get(Calendar.DAY_OF_MONTH));
+
+        assertEquals(15, value.get(Calendar.HOUR_OF_DAY));
+        assertEquals(11, value.get(Calendar.MINUTE));
+        assertEquals(24, value.get(Calendar.SECOND));
+    }
+
+    @Test
+    public void testTryParseCalendar_Invalid() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions().detectCalendarValues(true));
+        
+        Calendar value = underTest.tryParseCalendar("hello world");
+        assertNull(value);
+
+        value = underTest.tryParseCalendar("");
+        assertNull(value);
+
+        value = underTest.tryParseCalendar(null);
+        assertNull(value);
+    }
+
+    @Test
+    public void testTryParseCalendar_Disabled() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        
+        Calendar value = underTest.tryParseCalendar("Tue Apr 22 2014 15:11:24 GMT+0200");
+        assertNull(value);
+    }
+
+    @Test
+    public void testIgnoreProperty() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions().ignorePropertyNames(ImmutableSet.of("prop1", "jcr:prop2")));
+        
+        assertTrue(underTest.ignoreProperty("prop1"));
+        assertTrue(underTest.ignoreProperty("jcr:prop2"));
+        assertFalse(underTest.ignoreProperty("prop3"));
+    }
+
+    @Test
+    public void testIgnoreProperty_Disabled() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        
+        assertFalse(underTest.ignoreProperty("prop1"));
+        assertFalse(underTest.ignoreProperty("jcr:prop2"));
+        assertFalse(underTest.ignoreProperty("prop3"));
+    }
+
+    @Test
+    public void testIgnoreResource() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions().ignoreResourceNames(ImmutableSet.of("node1", "jcr:node2")));
+        
+        assertTrue(underTest.ignoreResource("node1"));
+        assertTrue(underTest.ignoreResource("jcr:node2"));
+        assertFalse(underTest.ignoreResource("node3"));
+    }
+
+    @Test
+    public void testIgnoreResource_Disabled() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        
+        assertFalse(underTest.ignoreResource("node1"));
+        assertFalse(underTest.ignoreResource("jcr:node2"));
+        assertFalse(underTest.ignoreResource("node3"));
+    }
+
+    @Test
+    public void testCleanupPropertyName() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+
+        assertEquals("prop1", underTest.cleanupPropertyName("jcr:reference:prop1"));
+        assertEquals("prop2", underTest.cleanupPropertyName("jcr:path:prop2"));
+        assertEquals("jcr:xyz:prop3", underTest.cleanupPropertyName("jcr:xyz:prop3"));
+    }
+
+    @Test
+    public void testCleanupPropertyName_Disabled() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions().removePropertyNamePrefixes(null));
+
+        assertEquals("jcr:reference:prop1", underTest.cleanupPropertyName("jcr:reference:prop1"));
+        assertEquals("jcr:path:prop2", underTest.cleanupPropertyName("jcr:path:prop2"));
+        assertEquals("jcr:xyz:prop3", underTest.cleanupPropertyName("jcr:xyz:prop3"));
+    }
+
+    @Test
+    public void testConvertSingleTypeArray() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+
+        assertArrayEquals(new Object[0], (Object[])underTest.convertSingleTypeArray(new Object[0]));
+        assertArrayEquals(new String[] {"value1","value2"}, (String[])underTest.convertSingleTypeArray(new Object[] {"value1","value2"}));
+        assertArrayEquals(new Long[] {1L,2L}, (Long[])underTest.convertSingleTypeArray(new Object[] {1L,2L}));
+    }
+
+    @Test(expected=ParseException.class)
+    public void testConvertSingleTypeArray_WithNull() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        underTest.convertSingleTypeArray(new Object[] {"value1",null});
+    }
+
+    @Test(expected=ParseException.class)
+    public void testConvertSingleTypeArray_Map() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        underTest.convertSingleTypeArray(new Object[] {ImmutableMap.<String,Object>of("prop1", "value1")});
+    }
+
+    @Test(expected=ParseException.class)
+    public void testConvertSingleTypeArray_MixedType() {
+        ParserHelper underTest = new ParserHelper(new ParserOptions());
+        underTest.convertSingleTypeArray(new Object[] {"value1",1L});
+    }
+
+}

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Mar  2 17:17:18 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/bundles/commons/fscontentparser/src/test/java/org/apache/sling/fscontentparser/impl/ParserHelperTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain