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/02/28 15:40:57 UTC

svn commit: r1784765 [3/5] - in /sling/branches/fsresource-1.1.x: ./ src/main/java/org/apache/sling/fsprovider/internal/ src/main/java/org/apache/sling/fsprovider/internal/mapper/ src/main/java/org/apache/sling/fsprovider/internal/mapper/jcr/ src/main/...

Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,62 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+import static org.apache.sling.fsprovider.internal.parser.ContentFileTypes.JCR_XML_SUFFIX;
+import static org.apache.sling.fsprovider.internal.parser.ContentFileTypes.JSON_SUFFIX;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Parses files that contains content fragments (e.g. JSON, JCR XML).
+ */
+class ContentFileParser {
+    
+    private static final Logger log = LoggerFactory.getLogger(ContentFileParser.class);
+    
+    private ContentFileParser() {
+        // static methods only
+    }
+    
+    /**
+     * Parse content from file.
+     * @param file File. Type is detected automatically.
+     * @return Content or null if content could not be parsed.
+     */
+    public static Map<String,Object> parse(File file) {
+        try {
+            if (StringUtils.endsWith(file.getName(), JSON_SUFFIX)) {
+                return JsonFileParser.parse(file);
+            }
+            else if (StringUtils.endsWith(file.getName(), JCR_XML_SUFFIX)) {
+                return JcrXmlFileParser.parse(file);
+            }
+        }
+        catch (Throwable ex) {
+            log.warn("Error parsing content from " + file.getPath(), ex);
+        }
+        return null;
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java Tue Feb 28 15:40:56 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.fsprovider.internal.parser;
+
+/**
+ * Content file types.
+ */
+public final class ContentFileTypes {
+    
+    /**
+     * JSON content files.
+     */
+    public static final String JSON_SUFFIX = ".json";
+
+    /**
+     * JCR XML content files.
+     */
+    public static final String JCR_XML_SUFFIX = ".jcr.xml";
+        
+    private ContentFileTypes() {
+        // static methods only
+    }
+    
+}

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/ContentFileTypes.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,147 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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.
+ */
+class JcrXmlFileParser {
+    
+    private static final Logger log = LoggerFactory.getLogger(JcrXmlFileParser.class);
+    
+    private static final SAXParserFactory SAX_PARSER_FACTORY;
+    static {
+        SAX_PARSER_FACTORY = SAXParserFactory.newInstance();
+        SAX_PARSER_FACTORY.setNamespaceAware(true);
+    }
+    
+    private JcrXmlFileParser() {
+        // static methods only
+    }
+    
+    /**
+     * Parse JSON file.
+     * @param file File
+     * @return Content
+     */
+    public static Map<String,Object> parse(File file) {
+        log.debug("Parse JCR XML content from {}", file.getPath());
+        try (FileInputStream fis = new FileInputStream(file)) {
+            XmlHandler xmlHandler = new XmlHandler();
+            SAXParser parser = SAX_PARSER_FACTORY.newSAXParser();
+            parser.parse(fis, xmlHandler);
+            if (xmlHandler.hasError()) {
+                throw xmlHandler.getError();
+            }
+            return xmlHandler.getContent();
+        }
+        catch (IOException | ParserConfigurationException | SAXException ex) {
+            log.warn("Error parsing JCR XML content from " + file.getPath(), ex);
+            return null;
+        }
+    }
+    
+    /**
+     * 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.
+     */
+    static 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<>();
+                elements.peek().put(decodeName(qName), element);
+            }
+            elements.push(element);
+            
+            // get attributes
+            for (int i=0; i<attributes.getLength(); i++) {
+                element.put(decodeName(attributes.getQName(i)), JcrXmlValueConverter.parseValue(attributes.getValue(i)));
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            elements.pop();
+        }
+
+        @Override
+        public void error(SAXParseException ex) throws SAXException {
+            this.error = ex;
+        }
+
+        @Override
+        public void fatalError(SAXParseException ex) throws SAXException {
+            this.error = ex;
+        }
+        
+    }
+    
+}

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java Tue Feb 28 15:40:56 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.fsprovider.internal.parser;
+
+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/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JcrXmlValueConverter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java (added)
+++ sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,125 @@
+/*
+ * 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.fsprovider.internal.parser;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Parses JSON files that contains content fragments.
+ */
+class JsonFileParser {
+    
+    private static final Logger log = LoggerFactory.getLogger(JsonFileParser.class);
+    
+    private static final JsonReaderFactory JSON_READER_FACTORY;
+    static {
+        // allow comments in JSON files
+        Map<String,Object> jsonReaderFactoryConfig = new HashMap<>();
+        jsonReaderFactoryConfig.put("org.apache.johnzon.supports-comments", true);
+        // workaround for JsonProvider classloader issue until https://issues.apache.org/jira/browse/GERONIMO-6560 is fixed
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(JsonFileParser.class.getClassLoader());
+            JSON_READER_FACTORY = Json.createReaderFactory(jsonReaderFactoryConfig);
+        }
+        finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+    }
+    
+    private JsonFileParser() {
+        // static methods only
+    }
+    
+    /**
+     * Parse JSON file.
+     * @param file File
+     * @return Content
+     */
+    public static Map<String,Object> parse(File file) {
+        log.debug("Parse JSON content from {}", file.getPath());
+        try (FileInputStream fis = new FileInputStream(file);
+                JsonReader reader = JSON_READER_FACTORY.createReader(fis)) {
+            return toMap(reader.readObject());
+        }
+        catch (IOException | JsonParsingException ex) {
+            log.warn("Error parsing JSON content from " + file.getPath(), ex);
+            return null;
+        }
+    }
+    
+    private static Map<String,Object> toMap(JsonObject object) {
+        Map<String,Object> map = new LinkedHashMap<>();
+        for (Map.Entry<String, JsonValue> entry : object.entrySet()) {
+            map.put(entry.getKey(), convertValue(entry.getValue()));
+        }
+        return map;
+    }
+    
+    private static Object convertValue(JsonValue value) {
+        switch (value.getValueType()) {
+            case STRING:
+                return ((JsonString)value).getString();
+            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 values;
+            case OBJECT:
+                return toMap((JsonObject)value);
+            default:
+                throw new IllegalArgumentException("Unexpected JSON value type: " + value.getValueType());
+        }
+    }
+    
+}

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/main/java/org/apache/sling/fsprovider/internal/parser/JsonFileParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,238 @@
+/*
+ * 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.fsprovider.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.fsprovider.internal.FileMonitor.ResourceChange;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.apache.sling.testing.mock.sling.junit.SlingContextCallback;
+import org.junit.Rule;
+import org.junit.Test;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+
+/**
+ * Test events when changing filesystem content.
+ */
+public class FileMonitorTest {
+
+    private final File tempDir;
+    private final EventAdminListener eventListener = new EventAdminListener();
+    
+    public FileMonitorTest() throws Exception {
+        tempDir = Files.createTempDirectory(getClass().getName()).toFile();
+    }
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .beforeSetUp(new SlingContextCallback() {
+            @Override
+            public void execute(SlingContext context) throws Exception {
+                // copy test content to temp. directory
+                tempDir.mkdirs();
+                File sourceDir = new File("src/test/resources/fs-test");
+                FileUtils.copyDirectory(sourceDir, tempDir);
+                
+                // mount temp. directory
+                context.registerInjectActivateService(new FsResourceProvider(),
+                        "provider.file", tempDir.getPath(),
+                        "provider.roots", "/fs-test",
+                        "provider.checkinterval", 120,
+                        "provider.json.content", true);
+                
+                // register resource change listener
+                context.registerService(EventHandler.class, eventListener,
+                        EventConstants.EVENT_TOPIC, new String[] {
+                                SlingConstants.TOPIC_RESOURCE_ADDED, 
+                                SlingConstants.TOPIC_RESOURCE_CHANGED,
+                                SlingConstants.TOPIC_RESOURCE_REMOVED
+                        });
+            }
+        })
+        .afterTearDown(new SlingContextCallback() {
+            @Override
+            public void execute(SlingContext context) throws Exception {
+                // remove temp directory
+                tempDir.delete();
+            }
+        })
+        .build();
+
+    @Test
+    public void testUpdateFile() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1a = new File(tempDir, "folder1/file1a.txt");
+        FileUtils.touch(file1a);
+        
+        Thread.sleep(250);
+
+        assertEquals(1, changes.size());
+        assertChange(changes, "/fs-test/folder1/file1a.txt", SlingConstants.TOPIC_RESOURCE_CHANGED);
+    }
+    
+    @Test
+    public void testAddFile() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1c = new File(tempDir, "folder1/file1c.txt");
+        FileUtils.write(file1c, "newcontent");
+        
+        Thread.sleep(250);
+
+        assertEquals(2, changes.size());
+        assertChange(changes, "/fs-test/folder1", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1c.txt", SlingConstants.TOPIC_RESOURCE_ADDED);
+    }
+    
+    @Test
+    public void testRemoveFile() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1a = new File(tempDir, "folder1/file1a.txt");
+        file1a.delete();
+        
+        Thread.sleep(250);
+
+        assertEquals(2, changes.size());
+        assertChange(changes, "/fs-test/folder1", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1a.txt", SlingConstants.TOPIC_RESOURCE_REMOVED);
+    }
+    
+    @Test
+    public void testAddFolder() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File folder99 = new File(tempDir, "folder99");
+        folder99.mkdir();
+        
+        Thread.sleep(250);
+
+        assertEquals(2, changes.size());
+        assertChange(changes, "/fs-test", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder99", SlingConstants.TOPIC_RESOURCE_ADDED);
+    }
+    
+    @Test
+    public void testRemoveFolder() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File folder1 = new File(tempDir, "folder1");
+        FileUtils.deleteDirectory(folder1);
+        
+        Thread.sleep(250);
+
+        assertEquals(2, changes.size());
+        assertChange(changes, "/fs-test", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1", SlingConstants.TOPIC_RESOURCE_REMOVED);
+    }
+
+    @Test
+    public void testUpdateJsonContent() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1a = new File(tempDir, "folder2/content.json");
+        FileUtils.touch(file1a);
+        
+        Thread.sleep(250);
+
+        assertTrue(changes.size() > 1);
+        assertChange(changes, "/fs-test/folder2/content", SlingConstants.TOPIC_RESOURCE_REMOVED);
+        assertChange(changes, "/fs-test/folder2/content", SlingConstants.TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/fs-test/folder2/content/jcr:content", SlingConstants.TOPIC_RESOURCE_ADDED);
+    }
+    
+    @Test
+    public void testAddJsonContent() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1c = new File(tempDir, "folder1/file1c.json");
+        FileUtils.write(file1c, "{\"prop1\":\"value1\",\"child1\":{\"prop2\":\"value1\"}}");
+        
+        Thread.sleep(250);
+
+        assertEquals(3, changes.size());
+        assertChange(changes, "/fs-test/folder1", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder1/file1c", SlingConstants.TOPIC_RESOURCE_ADDED);
+        assertChange(changes, "/fs-test/folder1/file1c/child1", SlingConstants.TOPIC_RESOURCE_ADDED);
+    }
+    
+    @Test
+    public void testRemoveJsonContent() throws Exception {
+        List<ResourceChange> changes = eventListener.getChanges();
+        assertTrue(changes.isEmpty());
+        
+        File file1a = new File(tempDir, "folder2/content.json");
+        file1a.delete();
+        
+        Thread.sleep(250);
+
+        assertEquals(2, changes.size());
+        assertChange(changes, "/fs-test/folder2", SlingConstants.TOPIC_RESOURCE_CHANGED);
+        assertChange(changes, "/fs-test/folder2/content", SlingConstants.TOPIC_RESOURCE_REMOVED);
+    }
+    
+    
+    private void assertChange(List<ResourceChange> changes, String path, String topic) {
+        boolean found = false;
+        for (ResourceChange change : changes) {
+            if (StringUtils.equals(change.path, path) && StringUtils.equals(change.topic,  topic)) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue("Change with path=" + path + ", topic=" + topic, found);
+    }
+    
+    static class EventAdminListener implements EventHandler {
+        private final List<ResourceChange> allChanges = new ArrayList<>();
+        public List<ResourceChange> getChanges() {
+            return allChanges;
+        }
+        @Override
+        public void handleEvent(Event event) {
+            ResourceChange change = new ResourceChange();
+            change.path = (String)event.getProperty(SlingConstants.PROPERTY_PATH);
+            change.resourceType = (String)event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE);
+            change.topic = event.getTopic();
+            allChanges.add(change);
+        }
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FileMonitorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,82 @@
+/*
+ * 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.fsprovider.internal;
+
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFile;
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFolder;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test access to files and folders from filesystem.
+ */
+public class FilesFolderTest {
+
+    private Resource root;
+    private Resource fsroot;
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .plugin(new RegisterFsResourcePlugin())
+        .build();
+
+    @Before
+    public void setUp() {
+        root = context.resourceResolver().getResource("/");
+        fsroot = context.resourceResolver().getResource("/fs-test");
+    }
+
+    @Test
+    public void testFolders() {
+        assertFolder(fsroot, "folder1");
+        assertFolder(fsroot, "folder1/folder11");
+        assertFolder(fsroot, "folder2");
+        assertFolder(fsroot, "folder3");
+    }
+
+    @Test
+    public void testFiles() {
+        assertFile(fsroot, "folder1/file1a.txt", "file1a");
+        assertFile(fsroot, "folder1/file1b.txt", "file1b");
+        assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
+        assertFile(fsroot, "folder2/content.json", null);
+        assertFile(fsroot, "folder2/content/file2content.txt", "file2content");
+        assertFile(fsroot, "folder3/content.jcr.xml", null);
+    }
+
+    @Test
+    public void testListChildren() {
+        assertThat(root, ResourceMatchers.containsChildren("fs-test"));
+        assertThat(fsroot, ResourceMatchers.hasChildren("folder1", "folder2", "folder3"));
+        assertThat(fsroot.getChild("folder1"), ResourceMatchers.hasChildren("folder11", "file1a.txt", "file1b.txt"));
+        assertThat(fsroot.getChild("folder2"), ResourceMatchers.hasChildren("folder21", "content.json"));
+        assertFalse(fsroot.getChild("folder1/file1a.txt").listChildren().hasNext());
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/FilesFolderTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,75 @@
+/*
+ * 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.fsprovider.internal;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.apache.sling.testing.mock.sling.junit.SlingContextCallback;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test with invalid fs folder.
+ */
+public class InvalidRootFolderTest {
+
+    private Resource fsroot;
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .plugin(new RegisterFsResourcePlugin("provider.file", "target/temp/invalid-folder"))
+        .afterTearDown(new SlingContextCallback() {
+            @Override
+            public void execute(SlingContext context) throws Exception {
+                File file = new File("target/temp/invalid-folder");
+                file.delete();
+            }
+        })
+        .build();
+
+    @Before
+    public void setUp() {
+        fsroot = context.resourceResolver().getResource("/fs-test");
+    }
+
+    @Test
+    public void testFolders() {
+        assertNull(fsroot.getChild("folder1"));
+    }
+
+    @Test
+    public void testFiles() {
+        assertNull(fsroot.getChild("folder1/file1a.txt"));
+    }
+
+    @Test
+    public void testListChildren() {
+        assertFalse(fsroot.listChildren().hasNext());
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/InvalidRootFolderTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,103 @@
+/*
+ * 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.fsprovider.internal;
+
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFile;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test access mixed with JCR content on same path.
+ */
+public class JcrMixedTest {
+
+    private Resource root;
+    private Resource fsroot;
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .plugin(new RegisterFsResourcePlugin())
+        .build();
+
+    @Before
+    public void setUp() throws RepositoryException {
+        root = context.resourceResolver().getResource("/");
+        fsroot = context.resourceResolver().getResource("/fs-test");
+        
+        // prepare mixed JCR content
+        Node node = root.adaptTo(Node.class);
+        Node fstest = node.addNode("fs-test", "nt:folder");
+        // folder1
+        Node folder1 = fstest.addNode("folder1", "nt:folder");
+        folder1.setProperty("prop1", "value1");
+        folder1.setProperty("prop2", 123L);
+        // folder1/file1a.txt
+        Node file1a = folder1.addNode("file1a.txt", "nt:file");
+        file1a.setProperty("prop1", "value2");
+        file1a.setProperty("prop2", 234L);
+        // folder1/file1c.txt
+        folder1.addNode("file1c.txt", "nt:file");
+        // folder99
+        fstest.addNode("folder99", "nt:folder");
+    }
+
+    @Test
+    public void testFolders() {
+        // expected properties from JCR for folders
+        Resource folder1 = fsroot.getChild("folder1");
+        assertThat(folder1, ResourceMatchers.props("jcr:primaryType", "nt:folder",
+                "prop1", "value1",
+                "prop2", 123L));
+    }
+
+    @Test
+    public void testFiles() {
+        assertFile(fsroot, "folder1/file1a.txt", "file1a");
+        assertFile(fsroot, "folder1/file1b.txt", "file1b");
+        assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
+        assertFile(fsroot, "folder2/content.json", null);
+
+        // do not expected properties from JCR for files
+        Resource file1a = fsroot.getChild("folder1/file1a.txt");
+        assertThat(file1a, not(ResourceMatchers.props(
+                "prop1", "value2",
+                "prop2", 234L)));
+    }
+
+    @Test
+    public void testListChildren() {
+        assertThat(root, ResourceMatchers.containsChildren("fs-test"));
+        assertThat(fsroot, ResourceMatchers.hasChildren("folder1", "folder2", "folder99"));
+        assertThat(fsroot.getChild("folder1"), ResourceMatchers.hasChildren("file1a.txt", "file1b.txt", "file1c.txt"));
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrMixedTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java Tue Feb 28 15:40:56 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.fsprovider.internal;
+
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFile;
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFolder;
+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.assertThat;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test access to files and folders from filesystem.
+ */
+public class JcrXmlContentTest {
+
+    private Resource root;
+    private Resource fsroot;
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .plugin(new RegisterFsResourcePlugin("provider.jcrxml.content", true))
+        .build();
+
+    @Before
+    public void setUp() {
+        root = context.resourceResolver().getResource("/");
+        fsroot = context.resourceResolver().getResource("/fs-test");
+    }
+
+    @Test
+    public void testFolders() {
+        assertFolder(fsroot, "folder1");
+        assertFolder(fsroot, "folder1/folder11");
+        assertFolder(fsroot, "folder2");
+        assertFolder(fsroot, "folder3");
+    }
+
+    @Test
+    public void testFiles() {
+        assertFile(fsroot, "folder1/file1a.txt", "file1a");
+        assertFile(fsroot, "folder1/file1b.txt", "file1b");
+        assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
+        assertFile(fsroot, "folder2/content.json", null);
+        assertNull(fsroot.getChild("folder3/content.jcr.xml"));
+    }
+
+    @Test
+    public void testListChildren() {
+        assertThat(root, ResourceMatchers.containsChildren("fs-test"));
+        assertThat(fsroot, ResourceMatchers.hasChildren("folder1", "folder2"));
+        assertThat(fsroot.getChild("folder1"), ResourceMatchers.hasChildren("folder11", "file1a.txt", "file1b.txt"));
+        assertThat(fsroot.getChild("folder2"), ResourceMatchers.hasChildren("folder21", "content"));
+    }
+
+    @Test
+    public void testJsonContent_Root() {
+        Resource underTest = fsroot.getChild("folder3/content");
+        assertNotNull(underTest);
+        assertEquals("app:Page", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertEquals("app:Page", underTest.getResourceType());
+        assertThat(underTest, ResourceMatchers.hasChildren("jcr:content"));
+    }
+
+    @Test
+    public void testJsonContent_Level1() {
+        Resource underTest = fsroot.getChild("folder3/content/jcr:content");
+        assertNotNull(underTest);
+        assertEquals("app:PageContent", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertEquals("samples/sample-app/components/content/page/homepage", underTest.getResourceType());
+        assertThat(underTest, ResourceMatchers.hasChildren("teaserbar", "aside", "content"));
+    }
+
+    @Test
+    public void testJsonContent_Level3() {
+        Resource underTest = fsroot.getChild("folder3/content/jcr:content/content/contentheadline");
+        assertNotNull(underTest);
+        assertEquals("nt:unstructured", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertEquals("samples/sample-app/components/content/common/contentHeadline", underTest.getResourceType());
+        assertFalse(underTest.listChildren().hasNext());
+    }
+
+    @Test
+    public void testJsonContent_Datatypes() {
+        Resource underTest = fsroot.getChild("folder3/content/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(underTest);
+        
+        assertEquals("en", props.get("jcr:title", String.class));
+        assertEquals(true, props.get("includeAside", false));
+        assertEquals((Long)1234567890123L, props.get("longProp", Long.class));
+        assertEquals((Double)1.2345d, props.get("decimalProp", Double.class), 0.00001d);
+        
+        assertArrayEquals(new String[] { "aa", "bb", "cc" }, props.get("stringPropMulti", String[].class));
+        assertArrayEquals(new Long[] { 1234567890123L, 55L }, props.get("longPropMulti", Long[].class));
+    }
+
+    @Test
+    public void testJsonContent_InvalidPath() {
+        Resource underTest = fsroot.getChild("folder2/content/jcr:content/xyz");
+        assertNull(underTest);
+    }
+
+    @Test
+    @Ignore  // jcr overlay is always active with the old sling resource provider API
+    public void testJcrMixedContent() throws RepositoryException {
+        // prepare mixed JCR content
+        Node node = root.adaptTo(Node.class);
+        Node fstest = node.addNode("fs-test", "nt:folder");
+        fstest.addNode("folder99", "nt:folder");
+
+        assertNull(fsroot.getChild("folder99"));
+    }
+
+    @Test
+    public void testFolder3ChildNodes() throws RepositoryException {
+        Resource folder3 = fsroot.getChild("folder3");
+        List<Resource> children = ImmutableList.copyOf(folder3.listChildren());
+        
+        assertEquals(2, children.size());
+        Resource child1 = children.get(0);
+        assertEquals("content", child1.getName());
+        assertEquals("app:Page", child1.getResourceType());
+        assertEquals("app:Page", ResourceUtil.getValueMap(child1).get("jcr:primaryType", String.class));
+
+        Resource child2 = children.get(1);
+        assertEquals("folder31", child2.getName());
+        assertEquals("nt:folder", ResourceUtil.getValueMap(child2).get("jcr:primaryType", String.class));
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JcrXmlContentTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,259 @@
+/*
+ * 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.fsprovider.internal;
+
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFile;
+import static org.apache.sling.fsprovider.internal.TestUtils.assertFolder;
+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.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.TestUtils.RegisterFsResourcePlugin;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Test access to files and folders from filesystem.
+ */
+public class JsonContentTest {
+
+    private Resource root;
+    private Resource fsroot;
+
+    @Rule
+    public SlingContext context = new SlingContextBuilder(ResourceResolverType.JCR_MOCK)
+        .plugin(new RegisterFsResourcePlugin("provider.json.content", true))
+        .build();
+
+    @Before
+    public void setUp() {
+        root = context.resourceResolver().getResource("/");
+        fsroot = context.resourceResolver().getResource("/fs-test");
+    }
+
+    @Test
+    public void testFolders() {
+        assertFolder(fsroot, "folder1");
+        assertFolder(fsroot, "folder1/folder11");
+        assertFolder(fsroot, "folder2");
+    }
+
+    @Test
+    public void testFiles() {
+        assertFile(fsroot, "folder1/file1a.txt", "file1a");
+        assertFile(fsroot, "folder1/file1b.txt", "file1b");
+        assertFile(fsroot, "folder1/folder11/file11a.txt", "file11a");
+        assertNull(fsroot.getChild("folder2/content.json"));
+        assertFile(fsroot, "folder2/content/file2content.txt", "file2content");
+        assertFile(fsroot, "folder3/content.jcr.xml", null);
+    }
+
+    @Test
+    public void testListChildren() {
+        assertThat(root, ResourceMatchers.containsChildren("fs-test"));
+        assertThat(fsroot, ResourceMatchers.hasChildren("folder1", "folder2"));
+        assertThat(fsroot.getChild("folder1"), ResourceMatchers.hasChildren("folder11", "file1a.txt", "file1b.txt"));
+        assertThat(fsroot.getChild("folder2"), ResourceMatchers.hasChildren("folder21", "content"));
+    }
+
+    @Test
+    public void testJsonContent_Root() {
+        Resource underTest = fsroot.getChild("folder2/content");
+        assertNotNull(underTest);
+        assertEquals("app:Page", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertEquals("app:Page", underTest.getResourceType());
+        assertThat(underTest, ResourceMatchers.hasChildren("jcr:content"));
+    }
+
+    @Test
+    public void testJsonContent_Level1() {
+        Resource underTest = fsroot.getChild("folder2/content/jcr:content");
+        assertNotNull(underTest);
+        assertEquals("app:PageContent", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertEquals("sample/components/homepage", underTest.getResourceType());
+        assertEquals("sample/components/supertype", underTest.getResourceSuperType());
+        assertThat(underTest, ResourceMatchers.hasChildren("par", "header", "newslist", "lead", "image", "carousel", "rightpar"));
+    }
+
+    @Test
+    public void testJsonContent_Level5() {
+        Resource underTest = fsroot.getChild("folder2/content/jcr:content/par/image/file/jcr:content");
+        assertNotNull(underTest);
+        assertEquals("nt:resource", ResourceUtil.getValueMap(underTest).get("jcr:primaryType", String.class));
+        assertFalse(underTest.listChildren().hasNext());
+    }
+
+    @Test
+    public void testJsonContent_Datatypes() {
+        Resource underTest = fsroot.getChild("folder2/content/toolbar/profiles/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(underTest);
+        
+        assertEquals("Profiles", props.get("jcr:title", String.class));
+        assertEquals(true, props.get("booleanProp", false));
+        assertEquals((Long)1234567890123L, props.get("longProp", Long.class));
+        assertEquals((Double)1.2345d, props.get("decimalProp", Double.class), 0.00001d);
+        
+        assertArrayEquals(new String[] { "aa", "bb", "cc" }, props.get("stringPropMulti", String[].class));
+        assertArrayEquals(new Long[] { 1234567890123L, 55L }, props.get("longPropMulti", Long[].class));
+    }
+
+    @Test
+    public void testJsonContent_Datatypes_JCR() throws RepositoryException {
+        Resource underTest = fsroot.getChild("folder2/content/toolbar/profiles/jcr:content");
+        ValueMap props = ResourceUtil.getValueMap(underTest);
+        Node node = underTest.adaptTo(Node.class);
+        
+        assertEquals("/fs-test/folder2/content/toolbar/profiles/jcr:content", node.getPath());
+        assertEquals(6, node.getDepth());
+        
+        assertTrue(node.hasProperty("jcr:title"));
+        assertEquals(PropertyType.STRING, node.getProperty("jcr:title").getType());
+        assertFalse(node.getProperty("jcr:title").isMultiple());
+        assertEquals("jcr:title", node.getProperty("jcr:title").getDefinition().getName());
+        assertEquals("/fs-test/folder2/content/toolbar/profiles/jcr:content/jcr:title", node.getProperty("jcr:title").getPath());
+        assertEquals("Profiles", node.getProperty("jcr:title").getString());
+        assertEquals(PropertyType.BOOLEAN, node.getProperty("booleanProp").getType());
+        assertEquals(true, node.getProperty("booleanProp").getBoolean());
+        assertEquals(PropertyType.LONG, node.getProperty("longProp").getType());
+        assertEquals(1234567890123L, node.getProperty("longProp").getLong());
+        assertEquals(PropertyType.DOUBLE, node.getProperty("decimalProp").getType());
+        assertEquals(1.2345d, node.getProperty("decimalProp").getDouble(), 0.00001d);
+        
+        assertEquals(PropertyType.STRING, node.getProperty("stringPropMulti").getType());
+        assertTrue(node.getProperty("stringPropMulti").isMultiple());
+        Value[] stringPropMultiValues = node.getProperty("stringPropMulti").getValues();
+        assertEquals(3, stringPropMultiValues.length);
+        assertEquals("aa", stringPropMultiValues[0].getString());
+        assertEquals("bb", stringPropMultiValues[1].getString());
+        assertEquals("cc", stringPropMultiValues[2].getString());
+
+        assertEquals(PropertyType.LONG, node.getProperty("longPropMulti").getType());
+        assertTrue(node.getProperty("longPropMulti").isMultiple());
+        Value[] longPropMultiValues = node.getProperty("longPropMulti").getValues();
+        assertEquals(2, longPropMultiValues.length);
+        assertEquals(1234567890123L, longPropMultiValues[0].getLong());
+        assertEquals(55L, longPropMultiValues[1].getLong());
+        
+        // assert property iterator
+        Set<String> propertyNames = new HashSet<>();
+        PropertyIterator propertyIterator = node.getProperties();
+        while (propertyIterator.hasNext()) {
+            propertyNames.add(propertyIterator.nextProperty().getName());
+        }
+        assertTrue(props.keySet().containsAll(propertyNames));
+
+        // assert node iterator
+        Set<String> nodeNames = new HashSet<>();
+        NodeIterator nodeIterator = node.getNodes();
+        while (nodeIterator.hasNext()) {
+            nodeNames.add(nodeIterator.nextNode().getName());
+        }
+        assertEquals(ImmutableSet.of("par", "rightpar"), nodeNames);
+        
+        // node hierarchy
+        assertTrue(node.hasNode("rightpar"));
+        Node rightpar = node.getNode("rightpar");
+        assertEquals(7, rightpar.getDepth());
+        Node parent = rightpar.getParent();
+        assertTrue(node.isSame(parent));
+        Node ancestor = (Node)rightpar.getAncestor(5);
+        assertEquals(underTest.getParent().getPath(), ancestor.getPath());
+        Node root = (Node)rightpar.getAncestor(0);
+        assertEquals("/", root.getPath());
+        
+        // node types
+        assertTrue(node.isNodeType("app:PageContent"));
+        assertEquals("app:PageContent", node.getPrimaryNodeType().getName());
+        assertFalse(node.getPrimaryNodeType().isMixin());
+        NodeType[] mixinTypes = node.getMixinNodeTypes();
+        assertEquals(2, mixinTypes.length);
+        assertEquals("type1", mixinTypes[0].getName());
+        assertEquals("type2", mixinTypes[1].getName());
+        assertTrue(mixinTypes[0].isMixin());
+        assertTrue(mixinTypes[1].isMixin());
+    }
+
+    @Test
+    public void testFallbackNodeType() throws RepositoryException {
+        Resource underTest = fsroot.getChild("folder2/content/jcr:content/par/title_2");
+        assertEquals(NodeType.NT_UNSTRUCTURED, underTest.adaptTo(Node.class).getPrimaryNodeType().getName());
+    }
+    
+    @Test
+    public void testJsonContent_InvalidPath() {
+        Resource underTest = fsroot.getChild("folder2/content/jcr:content/xyz");
+        assertNull(underTest);
+    }
+
+    @Test
+    @Ignore  // jcr overlay is always active with the old sling resource provider API
+    public void testJcrMixedContent() throws RepositoryException {
+        // prepare mixed JCR content
+        Node node = root.adaptTo(Node.class);
+        Node fstest = node.addNode("fs-test", "nt:folder");
+        fstest.addNode("folder99", "nt:folder");
+
+        assertNull(fsroot.getChild("folder99"));
+    }
+
+    @Test
+    public void testFolder2ChildNodes() throws RepositoryException {
+        Resource folder2 = fsroot.getChild("folder2");
+        List<Resource> children = ImmutableList.copyOf(folder2.listChildren());
+        
+        assertEquals(2, children.size());
+        Resource child1 = children.get(0);
+        assertEquals("content", child1.getName());
+        assertEquals("app:Page", child1.getResourceType());
+        assertEquals("app:Page", ResourceUtil.getValueMap(child1).get("jcr:primaryType", String.class));
+
+        Resource child2 = children.get(1);
+        assertEquals("folder21", child2.getName());
+        assertEquals("nt:folder", ResourceUtil.getValueMap(child2).get("jcr:primaryType", String.class));
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/JsonContentTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.fsprovider.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.hamcrest.ResourceMatchers;
+import org.apache.sling.testing.mock.osgi.MapUtil;
+import org.apache.sling.testing.mock.osgi.context.AbstractContextPlugin;
+import org.apache.sling.testing.mock.sling.context.SlingContextImpl;
+
+class TestUtils {
+
+    public static class RegisterFsResourcePlugin extends AbstractContextPlugin<SlingContextImpl> {
+        private final Map<String,Object> props;
+        public RegisterFsResourcePlugin(Object... props) {
+            this.props = MapUtil.toMap(props); 
+        }
+        @Override
+        public void beforeSetUp(SlingContextImpl context) throws Exception {
+            Map<String,Object> config = new HashMap<>();
+            config.put("provider.file", "src/test/resources/fs-test");
+            config.put("provider.roots", "/fs-test");
+            config.put("provider.checkinterval", 0);
+            config.putAll(props);
+            context.registerInjectActivateService(new FsResourceProvider(), config);
+        }
+    };
+
+    public static void assertFolder(Resource resource, String path) {
+        Resource folder = resource.getChild(path);
+        assertNotNull(path, folder);
+        
+        assertThat(folder, ResourceMatchers.props("jcr:primaryType", "nt:folder"));
+        assertEquals("nt:folder", folder.getResourceType());
+        
+        assertNull(folder.getResourceSuperType());
+        assertEquals(folder.getName(), folder.adaptTo(File.class).getName());
+        assertTrue(StringUtils.contains(folder.adaptTo(URL.class).toString(), folder.getName()));
+    }
+
+    public static void assertFile(Resource resource, String path, String content) {
+        Resource file = resource.getChild(path);
+        assertNotNull(path, file);
+        
+        assertThat(file, ResourceMatchers.props("jcr:primaryType", "nt:file"));
+        assertEquals("nt:file", file.getResourceType());
+        
+        assertNull(file.getResourceSuperType());
+        assertEquals(file.getName(), file.adaptTo(File.class).getName());
+        assertTrue(StringUtils.contains(file.adaptTo(URL.class).toString(), file.getName()));
+        
+        if (content != null) {
+            try {
+                try (InputStream is = file.adaptTo(InputStream.class)) {
+                    String data = IOUtils.toString(is, CharEncoding.UTF_8);
+                    assertEquals(content, data);
+                }
+            }
+            catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }    
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/TestUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,115 @@
+/*
+ * 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.fsprovider.internal.mapper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.fsprovider.internal.parser.ContentFileCache;
+import org.junit.Test;
+
+public class ContentFileTest {
+    
+    private ContentFileCache contentFileCache = new ContentFileCache(0);
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testRootContent() {
+        File file = new File("src/test/resources/fs-test/folder2/content.json");
+        
+        ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", null, contentFileCache);
+        assertEquals(file, underTest.getFile());
+        assertNull(underTest.getSubPath());
+        
+        assertTrue(underTest.hasContent());
+
+        Map<String,Object> content = (Map<String,Object>)underTest.getContent();
+        assertEquals("app:Page", content.get("jcr:primaryType"));
+        assertEquals("app:PageContent", ((Map<String,Object>)content.get("jcr:content")).get("jcr:primaryType"));
+
+        ValueMap props = underTest.getValueMap();
+        assertEquals("app:Page", props.get("jcr:primaryType"));
+        assertNull(props.get("jcr:content"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testContentLevel1() {
+        File file = new File("src/test/resources/fs-test/folder2/content.json");
+        
+        ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content", contentFileCache);
+        assertEquals(file, underTest.getFile());
+        assertEquals("jcr:content", underTest.getSubPath());
+        
+        assertTrue(underTest.hasContent());
+
+        Map<String,Object> content = (Map<String,Object>)underTest.getContent();
+        assertEquals("app:PageContent", content.get("jcr:primaryType"));
+
+        ValueMap props = underTest.getValueMap();
+        assertEquals("app:PageContent", props.get("jcr:primaryType"));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testContentLevel5() {
+        File file = new File("src/test/resources/fs-test/folder2/content.json");
+        
+        ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content/par/image/file/jcr:content", contentFileCache);
+        assertEquals(file, underTest.getFile());
+        assertEquals("jcr:content/par/image/file/jcr:content", underTest.getSubPath());
+        
+        assertTrue(underTest.hasContent());
+
+        Map<String,Object> content = (Map<String,Object>)underTest.getContent();
+        assertEquals("nt:resource", content.get("jcr:primaryType"));
+
+        ValueMap props = underTest.getValueMap();
+        assertEquals("nt:resource", props.get("jcr:primaryType"));
+    }
+
+    @Test
+    public void testContentProperty() {
+        File file = new File("src/test/resources/fs-test/folder2/content.json");
+        
+        ContentFile underTest = new ContentFile(file, "/fs-test/folder2/content", "jcr:content/jcr:title", contentFileCache);
+        assertEquals(file, underTest.getFile());
+        assertEquals("jcr:content/jcr:title", underTest.getSubPath());
+        
+        assertTrue(underTest.hasContent());
+
+        assertEquals("English", underTest.getContent());
+
+        assertTrue(underTest.getValueMap().isEmpty());
+    }
+
+    @Test
+    public void testInvalidFile() {
+        File file = new File("src/test/resources/fs-test/folder1/file1a.txt");
+        ContentFile underTest = new ContentFile(file, "/fs-test/folder1/file1a", null, contentFileCache);
+        assertFalse(underTest.hasContent());
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ContentFileTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java
URL: http://svn.apache.org/viewvc/sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java?rev=1784765&view=auto
==============================================================================
--- sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java (added)
+++ sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java Tue Feb 28 15:40:56 2017
@@ -0,0 +1,55 @@
+/*
+ * 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.fsprovider.internal.mapper;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class ValueMapUtilTest {
+
+    @Test
+    public void testToValueMap() {
+        Map<String,Object> content = new HashMap<>();
+        content.put("stringProp", "abc");
+        content.put("intProp", 123);
+        content.put("childNode", ImmutableMap.<String,Object>of());
+        content.put("stringArray", new String[] { "a", "b", "c" });
+        content.put("stringList", ImmutableList.of("ab", "cd"));
+        content.put("intList", ImmutableList.of(12, 34));
+        
+        ValueMap props = ValueMapUtil.toValueMap(content);
+        assertEquals("abc", props.get("stringProp", String.class));
+        assertEquals((Integer)123, props.get("intProp", 0));
+        assertNull(props.get("childNode"));
+        assertArrayEquals(new String[] { "a", "b", "c" }, props.get("stringArray", String[].class));
+        assertArrayEquals(new String[] { "ab", "cd" }, props.get("stringList", String[].class));
+        assertArrayEquals(new Integer[] { 12, 34 }, props.get("intList", Integer[].class));
+    }
+
+}

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Tue Feb 28 15:40:56 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/branches/fsresource-1.1.x/src/test/java/org/apache/sling/fsprovider/internal/mapper/ValueMapUtilTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain