Author: sseifert
Date: Wed May 20 12:53:50 2015
New Revision: 1680549

URL: http://svn.apache.org/r1680549
Log:
SLING-4381 generic nosql resource provider

Added:
    sling/trunk/contrib/nosql/
    sling/trunk/contrib/nosql/generic/
    sling/trunk/contrib/nosql/generic/pom.xml   (with props)
    sling/trunk/contrib/nosql/generic/src/
    sling/trunk/contrib/nosql/generic/src/main/
    sling/trunk/contrib/nosql/generic/src/main/java/
    sling/trunk/contrib/nosql/generic/src/main/java/org/
    sling/trunk/contrib/nosql/generic/src/main/java/org/apache/
    sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/
    sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
   (with props)
    sling/trunk/contrib/nosql/generic/src/test/
    sling/trunk/contrib/nosql/generic/src/test/java/
    sling/trunk/contrib/nosql/generic/src/test/java/org/
    sling/trunk/contrib/nosql/generic/src/test/java/org/apache/
    sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/
    sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTransactionalTest.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
   (with props)
    
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlResourceProviderFactory.java
   (with props)
    sling/trunk/contrib/nosql/generic/src/test/resources/
    sling/trunk/contrib/nosql/generic/src/test/resources/OSGI-INF/
    
sling/trunk/contrib/nosql/generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory.xml
   (with props)

Added: sling/trunk/contrib/nosql/generic/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/pom.xml?rev=1680549&view=auto
==============================================================================
--- sling/trunk/contrib/nosql/generic/pom.xml (added)
+++ sling/trunk/contrib/nosql/generic/pom.xml Wed May 20 12:53:50 2015
@@ -0,0 +1,139 @@
+<?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>22</version>
+    </parent>
+
+    <artifactId>org.apache.sling.nosql.generic</artifactId>
+    <version>0.5.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Generic NoSQL Resource Provider</name>
+
+    <scm>
+        
<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/nosql-generic</connection>
+        
<developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/nosql-generic</developerConnection>
+        
<url>http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/nosql-generic</url>
+    </scm>
+    
+    <properties>
+        <sling.java.version>7</sling.java.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+
+            <!-- Publish test artifact -->
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-jar-plugin</artifactId>
+              <executions>
+                <execution>
+                  <goals>
+                    <goal>test-jar</goal>
+                  </goals>
+                </execution>
+              </executions>
+            </plugin>
+  
+        </plugins>
+    </build>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.9.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.10.19</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+            <version>1.2.1-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>

Propchange: sling/trunk/contrib/nosql/generic/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/nosql/generic/pom.xml
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/nosql/generic/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,76 @@
+/*
+ * 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.nosql.generic.adapter;
+
+import java.util.Iterator;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Adapter for NoSQL databases to be hooked into the Generic NoSQL resource 
provider.
+ */
+@ConsumerType
+public interface NoSqlAdapter {
+    
+    /**
+     * True if the given path is valid and supported by the NoSQL database.
+     * @param path Path
+     * @return true if valid, false if invalid
+     */
+    boolean validPath(String path);
+
+    /**
+     * Get data for a single resource from NoSQL database.
+     * @param path Path
+     * @return Data or null if non exists
+     */
+    NoSqlData get(String path);
+
+    /**
+     * Get data for all children of a resource from NoSQL database.
+     * @param parentPath Parent path
+     * @return List if child data or empty iterator
+     */
+    Iterator<NoSqlData> getChildren(String parentPath);
+    
+    /**
+     * Store data with the given path in NoSQL database.
+     * It is guaranteed that the map of the NoSqlData object does only contain 
primitive
+     * value types String, Integer, Long, Double, Boolean or arrays of them.
+     * @param data Data with path
+     * @return true if a new entry was created, false if an existing was 
overridden.
+     */
+    boolean store(NoSqlData data);
+    
+    /**
+     * Remove data including all path-related children from NoSQL database.
+     * @param path Path to remove
+     * @return true if anything was removed
+     */
+    boolean deleteRecursive(String path);
+
+    /**
+     * Query for data.
+     * @param query Query
+     * @param language Query language
+     * @return Query result or null if query not supported
+     */
+    Iterator<NoSqlData> query(String query, String language);
+        
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,47 @@
+/*
+ * 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.nosql.generic.adapter;
+
+import java.util.Map;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * Wrapper for properties of a NoSQL document for a given path.
+ */
+@ProviderType
+public final class NoSqlData {
+
+    private final String path;
+    private final Map<String,Object> properties;
+    
+    public NoSqlData(String path, Map<String, Object> properties) {
+        this.path = path;
+        this.properties = properties;
+    }
+
+    public String getPath() {
+        return path;
+    }
+    
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+    
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
 Wed May 20 12:53:50 2015
@@ -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.
+ */
+/**
+ * Adapter for NoSQL resource provider implementation.
+ */
[email protected]("0.5")
+package org.apache.sling.nosql.generic.adapter;

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,51 @@
+/*
+ * 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.nosql.generic.resource;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.resource.impl.NoSqlResourceProvider;
+import org.osgi.service.event.EventAdmin;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Abstract implementation of resource provider factory.
+ * NoSQL resource providers implement this, add their own configuration 
support and and provide the matching NoSQL adapter implementation.
+ */
+@ConsumerType
+public abstract class AbstractNoSqlResourceProviderFactory implements 
ResourceProviderFactory {
+
+    public final ResourceProvider getResourceProvider(Map<String, Object> 
authenticationInfo) throws LoginException {
+        return new NoSqlResourceProvider(getNoSqlAdapter(), getEventAdmin());
+    }
+
+    public final ResourceProvider 
getAdministrativeResourceProvider(Map<String, Object> authenticationInfo) 
throws LoginException {
+        return getResourceProvider(authenticationInfo);
+    }
+    
+    protected abstract NoSqlAdapter getNoSqlAdapter();
+
+    protected abstract EventAdmin getEventAdmin();
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,90 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+import java.util.Map;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.AbstractResource;
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.DeepReadModifiableValueMapDecorator;
+import org.apache.sling.api.wrappers.DeepReadValueMapDecorator;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+
+/**
+ * Generic implementation of a NoSQL database resource.
+ */
+class NoSqlResource extends AbstractResource {
+    
+    private final NoSqlData data;
+    private final ResourceResolver resourceResolver;
+    private final NoSqlResourceProvider resourceProvider;
+    private final ResourceMetadata metadata;
+    
+    public NoSqlResource(NoSqlData data, ResourceResolver resourceResolver, 
NoSqlResourceProvider resourceProvider) {
+        this.data = data;
+        this.resourceResolver = resourceResolver;
+        this.resourceProvider = resourceProvider;
+        this.metadata = new ResourceMetadata();
+    }
+
+    public ResourceResolver getResourceResolver() {
+        return resourceResolver;
+    }
+
+    public String getPath() {
+        return data.getPath();
+    }
+
+    public String getResourceType() {
+        return getValueMap().get(ResourceResolver.PROPERTY_RESOURCE_TYPE, 
"nt:unstructured");
+    }
+
+    public String getResourceSuperType() {
+        return getValueMap().get(SlingConstants.NAMESPACE_PREFIX + ":" + 
SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE, String.class);
+    }
+
+    public ResourceMetadata getResourceMetadata() {
+        return metadata;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        if (type == ValueMap.class || type == Map.class) {
+            return (AdapterType)new DeepReadValueMapDecorator(this, new 
NoSqlValueMap(data.getProperties(), this, resourceProvider));
+        }
+        if (type == ModifiableValueMap.class) {
+            return (AdapterType)new DeepReadModifiableValueMapDecorator(this, 
new NoSqlValueMap(data.getProperties(), this, resourceProvider));
+        }
+        return super.adaptTo(type);
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName()
+            + ", type=" + getResourceType()
+            + ", superType=" + getResourceSuperType()
+            + ", path=" + getPath();
+    }
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,272 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.ModifyingResourceProvider;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.QueriableResourceProvider;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * Generic implementation of a NoSQL resource provider.
+ * The mapping to the NoSQL database implementation details is done via the 
provided {@link NoSqlAdapter}.
+ */
+public class NoSqlResourceProvider implements ResourceProvider, 
ModifyingResourceProvider, QueriableResourceProvider {
+    
+    private final NoSqlAdapter adapter;
+    private final EventAdmin eventAdmin;
+    private final Map<String, NoSqlData> changedResources = new 
HashMap<String, NoSqlData>();
+    private final Set<String> deletedResources = new HashSet<String>();
+    
+    public NoSqlResourceProvider(NoSqlAdapter adapter, EventAdmin eventAdmin) {
+        this.adapter = adapter;
+        this.eventAdmin = eventAdmin;
+    }
+
+    
+    // ### READONLY ACCESS ###
+    
+    public Resource getResource(ResourceResolver resourceResolver, String 
path) {
+        if (!adapter.validPath(path)) {
+            return null;
+        }
+        if (!this.deletedResources.isEmpty()) {
+            for (String deletedPath : deletedResources) {
+                Pattern deletedPathPattern = 
PathUtil.getSameOrDescendantPathPattern(deletedPath);
+                if (deletedPathPattern.matcher(path).matches()) {
+                    return null;
+                }
+            }
+        }
+        if (this.changedResources.containsKey(path)) {
+            return new NoSqlResource(this.changedResources.get(path), 
resourceResolver, this);
+        }
+        NoSqlData data = adapter.get(path);
+        if (data != null) {
+            return new NoSqlResource(data, resourceResolver, this);
+        }
+        return null;
+    }
+
+    public Resource getResource(ResourceResolver resourceResolver, 
HttpServletRequest request, String path) {
+        return getResource(resourceResolver, path);
+    }
+
+    public Iterator<Resource> listChildren(Resource parent) {
+        
+        // use map to consolidate data from adapter minus deleted plus changed 
resources
+        // always sorty result alphabetically to have a consistent ordering - 
the nosql data source does not support ordering
+        SortedMap<String, Resource> children = new TreeMap<String, Resource>();
+        
+        Iterator<NoSqlData> fromAdapter = 
adapter.getChildren(parent.getPath());
+        while (fromAdapter.hasNext()) {
+            NoSqlData item = fromAdapter.next();
+            if (isDeleted(item.getPath()) || 
changedResources.containsKey(item.getPath())) {
+                continue;
+            }
+            children.put(item.getPath(), new NoSqlResource(item, 
parent.getResourceResolver(), this));
+        }
+        
+        Pattern childPathPattern = 
PathUtil.getChildPathPattern(parent.getPath());
+        for (NoSqlData item : changedResources.values()) {
+            if (childPathPattern.matcher(item.getPath()).matches()) {
+                children.put(item.getPath(), new NoSqlResource(item, 
parent.getResourceResolver(), this));
+            }
+        }
+        
+        return children.values().iterator();
+    }
+
+    private boolean isDeleted(String path) {
+        for (String deletedPath : deletedResources) {
+            return path.equals(deletedPath) || path.equals(deletedPath + "/");
+        }
+        return false;
+    }
+
+    
+    // ### WRITE ACCESS ###
+    
+    public Resource create(ResourceResolver resolver, String path, Map<String, 
Object> properties)
+            throws PersistenceException {
+        if (!adapter.validPath(path)) {
+            throw new PersistenceException("Illegal path - unable to create 
resource at " + path, null, path, null);
+        }
+
+        // check if already exists
+        boolean deleted = this.deletedResources.remove(path);
+        boolean exists = changedResources.containsKey(path) || 
this.adapter.get(path) != null;
+        if (!deleted && exists) {
+            throw new PersistenceException("Resource already exists at " + 
path, null, path, null);
+        }
+        
+        // create new resource in changeset
+        NoSqlData data = new NoSqlData(path, 
NoSqlValueMap.convertForWriteAll(new HashMap<String, Object>(properties)));
+        changedResources.put(path, data);
+        return new NoSqlResource(data, resolver, this);
+    }
+    
+    public void delete(ResourceResolver resolver, String path) throws 
PersistenceException {
+        if (!adapter.validPath(path)) {
+            throw new PersistenceException("Unable to delete resource at {}" + 
path, null, path, null);
+        }
+
+        Pattern pathsToDeletePattern = 
PathUtil.getSameOrDescendantPathPattern(path);
+
+        // remove all existing path and probably descendant paths from list of 
deleted paths
+        Iterator<String> deletedResourcesIterator = 
deletedResources.iterator();
+        while (deletedResourcesIterator.hasNext()) {
+            String deletedPath = deletedResourcesIterator.next();
+            if (pathsToDeletePattern.matcher(deletedPath).matches()) {
+                deletedResourcesIterator.remove();
+            }
+        }
+        
+        // remove all changed descendant items from changeset
+        Iterator<Map.Entry<String, NoSqlData>> changeResourcesIterator = 
changedResources.entrySet().iterator();
+        while (changeResourcesIterator.hasNext()) {
+            Map.Entry<String, NoSqlData> entry = 
changeResourcesIterator.next();
+            if (pathsToDeletePattern.matcher(entry.getKey()).matches()) {
+                changeResourcesIterator.remove();
+            }
+        }
+        
+        // add path to delete
+        deletedResources.add(path);
+    }
+    
+    public void revert(ResourceResolver resolver) {
+        changedResources.clear();
+        deletedResources.clear();
+    }
+    
+    public void commit(ResourceResolver resolver) throws PersistenceException {
+        try {
+            for (String path : deletedResources) {
+               adapter.deleteRecursive(path); 
+               notifyRemoved(path);
+            }
+            for (NoSqlData item : changedResources.values()) {
+                boolean created = adapter.store(item);
+                if (created) {
+                    notifyAdded(item.getPath());
+                }
+                else {
+                    notifyUpdated(item.getPath());
+                }
+            }
+        }
+        finally {
+            this.revert(resolver);
+        }
+    }
+    
+    public boolean hasChanges(ResourceResolver resolver) {
+        return !(changedResources.isEmpty() && deletedResources.isEmpty());
+    }
+    
+    void markAsChanged(Resource resource) {
+        changedResources.put(resource.getPath(), new 
NoSqlData(resource.getPath(), resource.getValueMap()));
+    }
+    
+    private void notifyAdded(String path) {
+        final Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+        props.put(SlingConstants.PROPERTY_PATH, path);
+        props.put("event.distribute", "");
+        final Event event = new Event(SlingConstants.TOPIC_RESOURCE_ADDED, 
props);
+        this.eventAdmin.postEvent(event);
+    }
+
+    private void notifyUpdated(String path) {
+        final Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+        props.put(SlingConstants.PROPERTY_PATH, path);
+        props.put("event.distribute", "");
+        final Event event = new Event(SlingConstants.TOPIC_RESOURCE_CHANGED, 
props);
+        this.eventAdmin.postEvent(event);
+    }    
+
+    private void notifyRemoved(String path) {
+        final Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+        props.put(SlingConstants.PROPERTY_PATH, path);
+        props.put("event.distribute", "");
+        final Event event = new Event(SlingConstants.TOPIC_RESOURCE_REMOVED, 
props);
+        this.eventAdmin.postEvent(event);
+    }
+
+    
+    // ### QUERY ACCESS ###
+    
+    public Iterator<Resource> findResources(final ResourceResolver resolver, 
final String query, final String language) {
+        final Iterator<NoSqlData> result = adapter.query(query, language);
+        if (result == null) {
+            return null;
+        }
+        return new Iterator<Resource>() {
+            public boolean hasNext() {
+                return result.hasNext();
+            }
+            public Resource next() {
+                return new NoSqlResource(result.next(), resolver, 
NoSqlResourceProvider.this);
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Iterator<ValueMap> queryResources(final ResourceResolver resolver, 
final String query, final String language) {
+        final Iterator<Resource> result = findResources(resolver, query, 
language);
+        if (result == null) {
+            return null;
+        }
+        return new Iterator<ValueMap>() {
+            public boolean hasNext() {
+                return result.hasNext();
+            }
+            public ValueMap next() {
+                return result.next().getValueMap();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+    
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,178 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+
+/**
+ * Enhances ValueMap that adds special support for deep path access.
+ * Additionally date and binary types are converted to string and back when 
reading.
+ * Besides this only primitive types String, Integer, Long, Double, Boolean 
and arrays of them are supported.
+ */
+class NoSqlValueMap extends ValueMapDecorator implements ModifiableValueMap {
+    
+    private final Resource resource;
+    private final NoSqlResourceProvider resourceProvider;
+    
+    public NoSqlValueMap(Map<String,Object> map, Resource resource, 
NoSqlResourceProvider resourceProvider) {
+        super(convertForWriteAll(map));
+        this.resource = resource;
+        this.resourceProvider = resourceProvider;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T get(String name, Class<T> type) {
+        
+        if (type == Calendar.class) {
+            Date date = get(name, Date.class);
+            if (date != null) {
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(date);
+                return (T)calendar;
+            }
+            else {
+                return null;
+            }
+        }
+        else if (type == Date.class) {
+            Object value = get(name);
+            if (value instanceof String) {
+                try {
+                    return (T)getISO8601Format().parse((String)value);
+                } catch (ParseException e) {
+                    return null;
+                }
+            }
+        }
+        else if (type == InputStream.class) {
+            // Support conversion from byte array to InputStream
+            byte[] data = get(name, byte[].class);
+            if (data != null) {
+                return (T)new ByteArrayInputStream(data);
+            }
+            else {
+                return null;
+            }
+        }
+        else if (type == byte[].class) {
+            // Support conversion from base64 string to byte array
+            Object value = get(name);
+            if (value instanceof String) {
+                return (T)DatatypeConverter.parseBase64Binary((String)value);
+            }
+        }
+        else if ( type == null ) {
+            return (T) super.get(name);
+        }
+        return super.get(name, type);
+    }
+    
+    @Override
+    public Object put(String key, Object value) {
+        Object result = super.put(key, convertForWrite(value));
+        resourceProvider.markAsChanged(resource);
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void putAll(Map<? extends String, ?> map) {
+        super.putAll((Map<? extends String, ?>)convertForWriteAll((Map<String, 
Object>)map));
+        resourceProvider.markAsChanged(resource);
+    }
+    
+    @Override
+    public Object remove(Object key) {
+        Object result = super.remove(key);
+        resourceProvider.markAsChanged(resource);
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        super.clear();
+        resourceProvider.markAsChanged(resource);
+    }
+
+    private static Object convertForWrite(Object value) {
+        if (value instanceof Calendar) {
+            value = getISO8601Format().format(((Calendar)value).getTime());
+        }
+        if (value instanceof Date) {
+            value = getISO8601Format().format((Date)value);
+        }
+        else if (value instanceof InputStream) {
+            // Store InputStream values as byte array
+            try {
+                value = 
convertForWrite(IOUtils.toByteArray((InputStream)value));
+            } catch (IOException ex) {
+                throw new RuntimeException("Unable to convert input stream to 
byte array.");
+            }
+        }
+        else if (value instanceof byte[]) {
+            value = DatatypeConverter.printBase64Binary((byte[])value);
+        }
+        else if (value != null && !isValidPrimitveType(value.getClass())) {
+            throw new IllegalArgumentException("Data type not supported for 
NoSqlValueMap: " + value.getClass());
+        }
+        return value;
+    }
+    
+    static boolean isValidPrimitveType(Class clazz) {
+        if (clazz.isArray()) {
+            return isValidPrimitveType(clazz.getComponentType());
+        }
+        else {
+            return clazz == String.class
+                    || clazz == Integer.class
+                    || clazz == Long.class
+                    || clazz == Double.class
+                    || clazz == Boolean.class;
+        }
+    }
+    
+    public static Map<String, Object> convertForWriteAll(Map<String, Object> 
map) {
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            map.put(entry.getKey(), convertForWrite(entry.getValue()));
+        }
+        return map;
+    }
+
+    private static DateFormat getISO8601Format() {
+        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
+    }
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
 Wed May 20 12:53:50 2015
@@ -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.nosql.generic.resource.impl;
+
+import java.util.regex.Pattern;
+
+/**
+ * Helper functions for handling paths.
+ */
+public final class PathUtil {
+
+    private PathUtil() {
+        // static methods only
+    }
+    
+    /**
+     * Generated a regex pattern that accepts all paths that are direct 
children of the given parent path.
+     * @param parentPath Parent path
+     * @return Regex pattern
+     */
+    public static Pattern getChildPathPattern(String parentPath) {
+        return Pattern.compile("^" + Pattern.quote(parentPath) + "/[^/]+$");
+    }
+    
+    /**
+     * Generated a regex pattern that accepts all paths that are same or 
descendants of the given parent path.
+     * @param path Path
+     * @return Regex pattern
+     */
+    public static Pattern getSameOrDescendantPathPattern(String path) {
+        return Pattern.compile("^" + Pattern.quote(path) + "(/.*)?$");
+    }
+    
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
 Wed May 20 12:53:50 2015
@@ -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.
+ */
+/**
+ * Generic NoSQL resource provider implementation.
+ */
[email protected]("0.5")
+package org.apache.sling.nosql.generic.resource;

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,211 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+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.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public abstract class AbstractNoSqlResourceProviderTest {
+    
+    private static final String STRING_VALUE = "value1";
+    private static final String[] STRING_ARRAY_VALUE = new String[] { 
"value1", "value2" };
+    private static final int INTEGER_VALUE = 25;
+    private static final double DOUBLE_VALUE = 3.555d;
+    private static final boolean BOOLEAN_VALUE = true;
+    private static final Date DATE_VALUE = new Date(10000);
+    private static final Calendar CALENDAR_VALUE = Calendar.getInstance();
+    private static final byte[] BINARY_VALUE = new byte[] { 0x01, 0x02, 0x03, 
0x04, 0x05, 0x06 };
+
+    @Rule
+    public SlingContext context = new 
SlingContext(ResourceResolverType.JCR_MOCK);
+    
+    protected abstract void registerResourceProviderFactory();
+
+    protected abstract Resource testRoot();
+
+    @Before
+    public void setUp() throws Exception {
+        registerResourceProviderFactory();
+        
+        // prepare some test data using Sling CRUD API
+        Resource rootNode = testRoot();
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        props.put("stringProp", STRING_VALUE);
+        props.put("stringArrayProp", STRING_ARRAY_VALUE);
+        props.put("integerProp", INTEGER_VALUE);
+        props.put("doubleProp", DOUBLE_VALUE);
+        props.put("booleanProp", BOOLEAN_VALUE);
+        props.put("dateProp", DATE_VALUE);
+        props.put("calendarProp", CALENDAR_VALUE);
+        props.put("binaryProp", new ByteArrayInputStream(BINARY_VALUE));
+        Resource node1 = context.resourceResolver().create(rootNode, "node1", 
props);
+
+        context.resourceResolver().create(node1, "node11", 
ImmutableMap.<String, Object>builder()
+                .put("stringProp11", STRING_VALUE)
+                .build());
+        context.resourceResolver().create(node1, "node12", ValueMap.EMPTY);
+
+        context.resourceResolver().commit();
+    }
+    
+    @After
+    public void tearDown() {
+        context.resourceResolver().revert();
+        try {
+            context.resourceResolver().delete(testRoot());
+            context.resourceResolver().commit();
+        }
+        catch (PersistenceException ex) {
+            // ignore
+        }        
+    }
+
+    @Test
+    public void testSimpleProperties() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        assertTrue(resource1 instanceof NoSqlResource);
+        
+        assertNotNull(resource1);
+        assertEquals("node1", resource1.getName());
+
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(STRING_VALUE, props.get("stringProp", String.class));
+        assertArrayEquals(STRING_ARRAY_VALUE, props.get("stringArrayProp", 
String[].class));
+        assertEquals((Integer) INTEGER_VALUE, props.get("integerProp", 
Integer.class));
+        assertEquals(DOUBLE_VALUE, props.get("doubleProp", Double.class), 
0.0001);
+        assertEquals(BOOLEAN_VALUE, props.get("booleanProp", Boolean.class));
+    }
+
+    @Test
+    public void testSimpleProperties_DeepPathAccess() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath());
+        assertNotNull(resource1);
+        assertEquals(testRoot().getName(), resource1.getName());
+
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(STRING_VALUE, props.get("node1/stringProp", 
String.class));
+        assertArrayEquals(STRING_ARRAY_VALUE, 
props.get("node1/stringArrayProp", String[].class));
+        assertEquals((Integer) INTEGER_VALUE, props.get("node1/integerProp", 
Integer.class));
+        assertEquals(DOUBLE_VALUE, props.get("node1/doubleProp", 
Double.class), 0.0001);
+        assertEquals(BOOLEAN_VALUE, props.get("node1/booleanProp", 
Boolean.class));
+        assertEquals(STRING_VALUE, props.get("node1/node11/stringProp11", 
String.class));
+    }
+    
+    @Test
+    public void testDateProperty() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(DATE_VALUE, props.get("dateProp", Date.class));
+    }
+
+    @Test
+    public void testDatePropertyToCalendar() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        Calendar calendarValue = props.get("dateProp", Calendar.class);
+        assertNotNull(calendarValue);
+        assertEquals(DATE_VALUE, calendarValue.getTime());
+    }
+
+    @Test
+    public void testCalendarProperty() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        assertEquals(CALENDAR_VALUE.getTime(), props.get("calendarProp", 
Calendar.class).getTime());
+    }
+
+    @Test
+    public void testCalendarPropertyToDate() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        ValueMap props = ResourceUtil.getValueMap(resource1);
+        Date dateValue = props.get("calendarProp", Date.class);
+        assertNotNull(dateValue);
+        assertEquals(CALENDAR_VALUE.getTime(), dateValue);
+    }
+
+    @Test
+    public void testListChildren() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+
+        List<Resource> children = 
ImmutableList.copyOf(resource1.listChildren());
+        assertEquals(2, children.size());
+        assertEquals("node11", children.get(0).getName());
+        assertEquals("node12", children.get(1).getName());
+    }
+
+    @Test
+    public void testBinaryData() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+
+        InputStream is = ResourceUtil.getValueMap(resource1).get("binaryProp", 
InputStream.class);
+        byte[] dataFromResource = IOUtils.toByteArray(is);
+        is.close();
+        assertArrayEquals(BINARY_VALUE, dataFromResource);
+    }
+
+    @Test
+    public void testValueMapTypes() throws IOException {
+        Resource resource1 = 
context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+
+        // ensure that value map has only supported primitive types (all other 
supported types converted to string)
+        ValueMap valueMap = resource1.getValueMap();
+        for (Map.Entry<String, Object> entry : valueMap.entrySet()) {
+            
assertTrue(NoSqlValueMap.isValidPrimitveType(entry.getValue().getClass()));
+        }
+    }
+
+    @Test
+    public void testPrimaryTypeResourceType() throws PersistenceException {
+        Resource resource = 
context.resourceResolver().getResource(testRoot().getPath());
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, resource.getResourceType());
+    }
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,227 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+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.Iterator;
+
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public abstract class AbstractNoSqlResourceProviderTransactionalTest {
+    
+    @Rule
+    public SlingContext context = new 
SlingContext(ResourceResolverType.JCR_MOCK);
+    
+    protected abstract void registerResourceProviderFactory();
+
+    protected abstract Resource testRoot();
+
+    @Before
+    public void setUp() throws Exception {
+        registerResourceProviderFactory();
+    }
+    
+    @After
+    public void tearDown() {
+        context.resourceResolver().revert();
+        try {
+            context.resourceResolver().delete(testRoot());
+            context.resourceResolver().commit();
+        }
+        catch (PersistenceException ex) {
+            // ignore
+        }        
+    }
+
+    @Test
+    public void testRootNode() {
+        assertTrue(testRoot() instanceof NoSqlResource);
+    }
+
+    @Test
+    public void testAddDeleteNodesPartialCommit() throws PersistenceException {
+        context.resourceResolver().create(testRoot(), "node0", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().create(testRoot(), "node2", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot(), "node3", 
ImmutableMap.<String, Object>of());
+
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot().getChild("node0"));
+        assertNotNull(testRoot().getChild("node1"));
+        assertNotNull(testRoot().getChild("node2"));
+        assertNotNull(testRoot().getChild("node3"));
+        
+        context.resourceResolver().delete(testRoot().getChild("node0"));
+        context.resourceResolver().delete(testRoot().getChild("node2"));
+
+        assertNull(testRoot().getChild("node0"));
+        assertNotNull(testRoot().getChild("node1"));
+        assertNull(testRoot().getChild("node2"));
+        assertNotNull(testRoot().getChild("node3"));
+        
+        Iterator<Resource> children = testRoot().listChildren();
+        assertEquals("node1", children.next().getName());
+        assertEquals("node3", children.next().getName());
+        assertFalse(children.hasNext());
+        
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().revert();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot().getChild("node1"));
+        assertNull(testRoot().getChild("node2"));
+        assertNull(testRoot().getChild("node3"));
+        
+        children = testRoot().listChildren();
+        assertEquals("node0", children.next().getName());
+        assertEquals("node1", children.next().getName());
+        assertFalse(children.hasNext());
+    }
+
+    @Test
+    public void testRecursiveDeleteWithoutCommit() throws PersistenceException 
{
+        Resource node1 = context.resourceResolver().create(testRoot(), 
"node1", ImmutableMap.<String, Object>of());
+        Resource node11 = context.resourceResolver().create(node1, "node11", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(node11, "node111", 
ImmutableMap.<String, Object>of());
+
+        assertNotNull(testRoot().getChild("node1"));
+        assertNotNull(testRoot().getChild("node1/node11"));
+        assertNotNull(testRoot().getChild("node1/node11/node111"));
+        
+        context.resourceResolver().delete(node1);
+
+        assertNull(testRoot().getChild("node1"));
+        assertNull(testRoot().getChild("node1/node11"));
+        assertNull(testRoot().getChild("node1/node11/node111"));
+    }
+
+    @Test
+    public void testRecursiveDeleteWithCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot(), 
"node1", ImmutableMap.<String, Object>of());
+        Resource node11 = context.resourceResolver().create(node1, "node11", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(node11, "node111", 
ImmutableMap.<String, Object>of());
+        
+        assertTrue(context.resourceResolver().hasChanges());
+        
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+        
+        assertNotNull(testRoot().getChild("node1"));
+        assertNotNull(testRoot().getChild("node1/node11"));
+        assertNotNull(testRoot().getChild("node1/node11/node111"));
+        
+        context.resourceResolver().delete(node1);
+
+        assertNull(testRoot().getChild("node1"));
+        assertNull(testRoot().getChild("node1/node11"));
+        assertNull(testRoot().getChild("node1/node11/node111"));
+
+        assertTrue(context.resourceResolver().hasChanges());
+
+        context.resourceResolver().commit();
+
+        assertFalse(context.resourceResolver().hasChanges());
+
+        assertNull(testRoot().getChild("node1"));
+        assertNull(testRoot().getChild("node1/node11"));
+        assertNull(testRoot().getChild("node1/node11/node111"));
+    }
+
+    @Test(expected = PersistenceException.class)
+    public void testCreateAlreadyExistWithoutCommit() throws 
PersistenceException {
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+    }
+    
+    @Test(expected = PersistenceException.class)
+    public void testCreateAlreadyExistWithCommit() throws PersistenceException 
{
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testCreateAlreadyExistDeletedWithoutCommit() throws 
PersistenceException {
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().delete(testRoot().getChild("node1"));
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testCreateAlreadyExistDeletedWithCommit() throws 
PersistenceException {
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+        context.resourceResolver().commit();
+        context.resourceResolver().delete(testRoot().getChild("node1"));
+        context.resourceResolver().commit();
+        context.resourceResolver().create(testRoot(), "node1", 
ImmutableMap.<String, Object>of());
+    }
+    
+    @Test
+    public void testUpdateWithoutCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot(), 
"node1", ImmutableMap.<String, Object>of("prop1", "value1"));
+        assertEquals("value1", node1.getValueMap().get("prop1", String.class));
+        
+        ModifiableValueMap props = node1.adaptTo(ModifiableValueMap.class);
+        props.put("prop1", "value2");
+        
+        node1 = testRoot().getChild("node1");
+        assertEquals("value2", node1.getValueMap().get("prop1", String.class));
+    }
+    
+    @Test
+    public void testUpdateWithCommit() throws PersistenceException {
+        Resource node1 = context.resourceResolver().create(testRoot(), 
"node1", ImmutableMap.<String, Object>of("prop1", "value1"));
+        assertEquals("value1", node1.getValueMap().get("prop1", String.class));
+        context.resourceResolver().commit();
+        
+        ModifiableValueMap props = node1.adaptTo(ModifiableValueMap.class);
+        props.put("prop1", "value2");
+        context.resourceResolver().commit();
+        
+        node1 = testRoot().getChild("node1");
+        assertEquals("value2", node1.getValueMap().get("prop1", String.class));
+    }
+    
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,56 @@
+/*
+ * 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.nosql.generic.resource.impl;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.regex.Pattern;
+
+import org.junit.Test;
+
+public class PathUtilTest {
+
+    @Test
+    public void testGetChildPathPattern() {
+        Pattern pattern = PathUtil.getChildPathPattern("/my/path");
+        
+        assertFalse(pattern.matcher("/my/path").matches());
+        assertTrue(pattern.matcher("/my/path/child1").matches());
+        assertTrue(pattern.matcher("/my/path/child2").matches());
+        assertFalse(pattern.matcher("/my/path/child1/subchild1").matches());
+        
assertFalse(pattern.matcher("/my/path/child1/subchild1/subchild2").matches());
+        assertFalse(pattern.matcher("/my/sibling").matches());
+        assertFalse(pattern.matcher("/other").matches());
+    }
+
+    @Test
+    public void testGetDescendantPathPattern() {
+        Pattern pattern = PathUtil.getSameOrDescendantPathPattern("/my/path");
+        
+        assertTrue(pattern.matcher("/my/path").matches());
+        assertTrue(pattern.matcher("/my/path/child1").matches());
+        assertTrue(pattern.matcher("/my/path/child2").matches());
+        assertTrue(pattern.matcher("/my/path/child1/subchild1").matches());
+        
assertTrue(pattern.matcher("/my/path/child1/subchild1/subchild2").matches());
+        assertFalse(pattern.matcher("/my/sibling").matches());
+        assertFalse(pattern.matcher("/other").matches());
+    }
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,102 @@
+/*
+ * 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.nosql.generic.simple;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import 
org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class SimpleNoSqlResourceProviderQueryTest {
+    
+    @Rule
+    public SlingContext context = new 
SlingContext(ResourceResolverType.JCR_MOCK);
+    
+    private Resource testRoot;
+
+    @Before
+    public void setUp() throws Exception {
+        context.registerInjectActivateService(new 
SimpleNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/nosql-simple")
+                .build());
+        
+        // prepare some test data using Sling CRUD API
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+        final Resource root = context.resourceResolver().getResource("/");
+        Resource noSqlRoot = context.resourceResolver().create(root, 
"nosql-simple", props);
+        this.testRoot = context.resourceResolver().create(noSqlRoot, "test", 
props);
+        
+        context.resourceResolver().create(testRoot, "node1", 
ImmutableMap.<String, Object>of("prop1", "value1"));
+        context.resourceResolver().create(testRoot, "node2", 
ImmutableMap.<String, Object>of("prop1", "value2"));
+        
+        context.resourceResolver().commit();
+    }
+
+    @Test
+    public void testFindResources_ValidQuery() {
+        Iterator<Resource> result = 
context.resourceResolver().findResources("all", "simple");
+        assertEquals("/nosql-simple", result.next().getPath());
+        assertEquals("/nosql-simple/test", result.next().getPath());
+        assertEquals("/nosql-simple/test/node1", result.next().getPath());
+        assertEquals("/nosql-simple/test/node2", result.next().getPath());
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testFindResources_InvalidQuery() {
+        Iterator<Resource> result = 
context.resourceResolver().findResources("all", "invalid");
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testQueryResources_ValidQuery() {
+        Iterator<Map<String, Object>> result = 
context.resourceResolver().queryResources("all", "simple");
+        assertNull(result.next().get("prop1"));
+        assertNull(result.next().get("prop1"));
+        assertEquals("value1", result.next().get("prop1"));
+        assertEquals("value2", result.next().get("prop1"));
+        assertFalse(result.hasNext());
+    }
+
+    @Test
+    public void testQueryResources_InvalidQuery() {
+        Iterator<Map<String, Object>> result = 
context.resourceResolver().queryResources("all", "invalid");
+        assertFalse(result.hasNext());
+    }
+
+}

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Wed May 20 12:53:50 2015
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java?rev=1680549&view=auto
==============================================================================
--- 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
 (added)
+++ 
sling/trunk/contrib/nosql/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
 Wed May 20 12:53:50 2015
@@ -0,0 +1,64 @@
+/*
+ * 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.nosql.generic.simple;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import 
org.apache.sling.nosql.generic.resource.impl.AbstractNoSqlResourceProviderTest;
+import 
org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class SimpleNoSqlResourceProviderTest extends 
AbstractNoSqlResourceProviderTest {
+    
+    private Resource testRoot;
+
+    @Override
+    protected void registerResourceProviderFactory() {
+        context.registerInjectActivateService(new 
SimpleNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/nosql-simple")
+                .build());
+    }
+
+    @Override
+    protected Resource testRoot() {
+        if (this.testRoot == null) {
+            try {
+                Map<String, Object> props = new HashMap<String, Object>();
+                props.put(JcrConstants.JCR_PRIMARYTYPE, 
JcrConstants.NT_UNSTRUCTURED);
+                final Resource root = 
context.resourceResolver().getResource("/");
+                Resource noSqlRoot = context.resourceResolver().create(root, 
"nosql-simple", props);
+                this.testRoot = context.resourceResolver().create(noSqlRoot, 
"test", props);
+            }
+            catch (PersistenceException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return this.testRoot;
+    }
+
+}


Reply via email to