You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:56:27 UTC

[sling-org-apache-sling-nosql-generic] annotated tag org.apache.sling.nosql.generic-1.1.0 created (now 734c981)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git.


      at 734c981  (tag)
 tagging ea84c17d127577a8b2e4a125cac5ab6515e6b0e0 (commit)
      by Stefan Seifert
      on Wed Feb 24 12:04:51 2016 +0000

- Log -----------------------------------------------------------------
org.apache.sling.nosql.generic-1.1.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new c0cfaf5  SLING-4381 generic nosql resource provider
     new 33067de  SLING-4381 couchbase client
     new d611ecf  SLING-4381 fix problem with deleted resources; define profile for integration tests
     new 5a39f50  SLING-4381 add READMEs, make factory configuration
     new a75ba5e  SLING-4381 add special handling for root resource
     new 97f137a  SLING-4381 disallow storing data in root resource
     new 1254cfe  SLING-4381 fix logic error for buckets with password; update readme
     new 330fa60  SLING-4381 allow null map when creating a resource
     new 6bace0b  SLING-4381 enable metrics logging for nosql adapter and disable event distribution
     new 3f2b8af  SLING-4381 metrics logging
     new 7233de3  SLING-4381 introduce AbstractNoSqlAdapter
     new 9083d70  update to released mock versions
     new f2ba0f2  SLING-4381 keep Calendar and byte[] types in ValueMap, and convert it from and back when passing over to NoSql adapter
     new b8a97cb  Update contrib modules to Parent 23
     new ef63139  set parent version to 24 and add empty relativePath where missing
     new 0e42677  SLING-4881 NoSQL Generic Resource Provider: Preserve order of changed resources (patch contributed by Levente Santha)
     new e5ad3dd  Added Eclipse files to svn:ignore in the new contrib bundles
     new a125fa9  SLING-5024 Sling NoSQL Resource Provider for MongoDB (based on nosql.generic)
     new 1c42a40  SLING-4381/SLING-5024 fix root node child listing
     new f3a77c7  cosmetic: fix javadoc errors
     new 3a6aa25  prepare 1.0.0 release
     new 72c4eb4  [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.0.0
     new bece24f  [maven-release-plugin] prepare for next development iteration
     new a9f1532  Update the contrib reactor to parent 25
     new 44e42e6  Switch to parent pom 26
     new 2c43a9f  SLING-5437 The NoSQL providers should throw LoginException if the connection to the NoSQL database can't be established (patch provided by Robert Munteanu)
     new 6f719ec  SLING-5437 add connection check for couchbase resource provider define separate NoSqlAdapter methods for creating index definitions, to ensure they are only executed after connection test succeeds set versions to 1.1.0
     new df91c50  SLING-5151 NoSQL: allow modifying the root resource
     new e040f95  [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
     new 7629960  [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0
     new 8bc5a94  [maven-release-plugin] prepare for next development iteration
     new 12436f0  [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0
     new e6d3010  update package version to 1.0 because we had a major package version update anyway in this release
     new ac3a598  [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
     new f92bfcd  [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0
     new 1cc31d3  [maven-release-plugin] prepare for next development iteration
     new bbd89ef  [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0
     new 6c8333d  exclude README.md in rat report
     new 24581c4  [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
     new ea84c17  [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0

The 40 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-nosql-generic] 12/18: [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit ac3a59805d700576ea95bfb158fa56dd133d7020
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:54:30 2016 +0000

    [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732088 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 81d45fe..5b596b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.0-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 05/18: SLING-5437 add connection check for couchbase resource provider define separate NoSqlAdapter methods for creating index definitions, to ensure they are only executed after connection test succeeds set versions to 1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 6f719ec60f33407bf4da3f26fd95971379b1fb91
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Jan 19 17:47:07 2016 +0000

    SLING-5437 add connection check for couchbase resource provider
    define separate NoSqlAdapter methods for creating index definitions, to ensure they are only executed after connection test succeeds
    set versions to 1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1725576 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                                          | 2 +-
 .../apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java | 7 -------
 .../sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java  | 7 ++++++-
 .../org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java     | 9 ++++++++-
 .../generic/resource/AbstractNoSqlResourceProviderFactory.java   | 1 +
 .../generic/resource/impl/ValueMapConvertingNoSqlAdapter.java    | 5 +++++
 .../sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java  | 5 +++++
 7 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/pom.xml b/pom.xml
index d9f2288..81d45fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.0.1-SNAPSHOT</version>
+    <version>1.1.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
index d8672e6..38eff2b 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
@@ -20,8 +20,6 @@ package org.apache.sling.nosql.generic.adapter;
 
 import java.util.Iterator;
 
-import org.apache.sling.api.resource.LoginException;
-
 import aQute.bnd.annotation.ConsumerType;
 
 /**
@@ -42,9 +40,4 @@ public abstract class AbstractNoSqlAdapter implements NoSqlAdapter {
         return null;
     }
     
-    @Override
-    public void checkConnection() throws LoginException {
-        // not supported unless it is overwritten explicitly
-    }
-
 }
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java b/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
index 68a8381..319406f 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
@@ -95,6 +95,11 @@ public final class MetricsNoSqlAdapterWrapper implements NoSqlAdapter {
         delegate.checkConnection();
     }
 
+    @Override
+    public void createIndexDefinitions() {
+        delegate.createIndexDefinitions();
+    }    
+
     private class Metrics {
         
         private long startTime;
@@ -113,5 +118,5 @@ public final class MetricsNoSqlAdapterWrapper implements NoSqlAdapter {
         }
         
     }
-    
+
 }
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
index d86cd29..fb4d3e9 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
@@ -78,9 +78,16 @@ public interface NoSqlAdapter {
 
     /**
      * Checks whether the connection to the NoSQL database is possible
-     *
      * @throws LoginException in case of any errors
      */
     void checkConnection() throws LoginException;
 
+    /**
+     * Creates index definitions for accessing the NoSQL database.
+     * This is called every time an adapter instances is created. If the indexes are
+     * already present it should do nothing.
+     * It is only called when the {@link #checkConnection()} call succeeds.
+     */
+    void createIndexDefinitions();
+
 }
diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java b/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
index c1e7811..47be2fe 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
@@ -39,6 +39,7 @@ public abstract class AbstractNoSqlResourceProviderFactory implements ResourcePr
     public final ResourceProvider getResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
         NoSqlAdapter adapter = getNoSqlAdapter();
         adapter.checkConnection();
+        adapter.createIndexDefinitions();
         return new NoSqlResourceProvider(adapter, getEventAdmin());
     }
 
diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
index 52ef419..37e3c45 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
@@ -169,6 +169,11 @@ class ValueMapConvertingNoSqlAdapter implements NoSqlAdapter {
         delegate.checkConnection();
     }
 
+    @Override
+    public void createIndexDefinitions() {
+        delegate.createIndexDefinitions();
+    }
+
     private static DateFormat getISO8601Format() {
         return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
     }
diff --git a/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java b/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
index 6702e1a..89da8b1 100644
--- a/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
+++ b/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
@@ -117,7 +117,12 @@ public class SimpleNoSqlAdapter implements NoSqlAdapter {
 
     @Override
     public void checkConnection() throws LoginException {
+        // nothing to do
+    }
 
+    @Override
+    public void createIndexDefinitions() {
+        // nothing to do
     }
 
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 07/18: [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit e040f95d2fcf8be1dc09927675d4481e0b7d17e0
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:51:02 2016 +0000

    [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732082 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 81d45fe..5b596b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.0-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 09/18: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 8bc5a947cd6e552f862a90a35c463d395b19aaf3
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:51:17 2016 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732084 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5b596b7..f136b8a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.0</version>
+    <version>1.1.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 03/18: Switch to parent pom 26

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 44e42e647a380d221c8625f96b82f8618db0ae30
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Sun Jan 3 14:07:46 2016 +0000

    Switch to parent pom 26
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1722720 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 3d92fe5..d9f2288 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>25</version>
+        <version>26</version>
         <relativePath />
     </parent>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 13/18: [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit f92bfcd831065782735b554a0ecd8c4bbbbb1e3d
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:54:46 2016 +0000

    [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0@1732089 13f79535-47bb-0310-9956-ffa450edef68
---
 generic/README.md                                  |  16 ++
 generic/pom.xml                                    | 154 ++++++++++++
 .../generic/adapter/AbstractNoSqlAdapter.java      |  43 ++++
 .../sling/nosql/generic/adapter/MapConverter.java  |  87 +++++++
 .../adapter/MetricsNoSqlAdapterWrapper.java        | 122 +++++++++
 .../nosql/generic/adapter/MultiValueMode.java      |  36 +++
 .../sling/nosql/generic/adapter/NoSqlAdapter.java  |  93 +++++++
 .../sling/nosql/generic/adapter/NoSqlData.java     |  71 ++++++
 .../sling/nosql/generic/adapter/package-info.java  |  23 ++
 .../AbstractNoSqlResourceProviderFactory.java      |  54 ++++
 .../nosql/generic/resource/impl/NoSqlResource.java |  90 +++++++
 .../resource/impl/NoSqlResourceProvider.java       | 280 +++++++++++++++++++++
 .../nosql/generic/resource/impl/NoSqlValueMap.java | 147 +++++++++++
 .../nosql/generic/resource/impl/PathUtil.java      |  52 ++++
 .../impl/ValueMapConvertingNoSqlAdapter.java       | 181 +++++++++++++
 .../sling/nosql/generic/resource/package-info.java |  23 ++
 .../nosql/generic/adapter/MapConverterTest.java    |  79 ++++++
 .../AbstractNoSqlResourceProviderRootTest.java     | 133 ++++++++++
 .../impl/AbstractNoSqlResourceProviderTest.java    | 217 ++++++++++++++++
 ...ractNoSqlResourceProviderTransactionalTest.java | 227 +++++++++++++++++
 .../nosql/generic/resource/impl/PathUtilTest.java  |  56 +++++
 .../SimpleNoSqlResourceProviderQueryTest.java      | 102 ++++++++
 .../SimpleNoSqlResourceProviderRootTest.java       |  39 +++
 .../simple/SimpleNoSqlResourceProviderTest.java    |  64 +++++
 ...mpleNoSqlResourceProviderTransactionalTest.java |  73 ++++++
 .../simple/provider/SimpleNoSqlAdapter.java        | 128 ++++++++++
 .../SimpleNoSqlResourceProviderFactory.java        |  77 ++++++
 ...provider.SimpleNoSqlResourceProviderFactory.xml |  32 +++
 28 files changed, 2699 insertions(+)

diff --git a/generic/README.md b/generic/README.md
new file mode 100644
index 0000000..3c2efba
--- /dev/null
+++ b/generic/README.md
@@ -0,0 +1,16 @@
+Apache Sling NoSQL Generic Resource Provider
+============================================
+
+Generic implementation of a Sling ResourceProvider that helps writing ResourceProviders using NoSQL databases as persistence.
+
+The generic implementation helps mapping the resource data to document-oriented key-value NoSQL databases like MongoDB or Couchbase.
+
+Features:
+
+* Defines a simplified "NoSqlAdapter" concept that is implemented for each NoSQL database. It boils down to simple get/put/list operations. Query support is optional.
+* Complete implementation of Resource, ResourceProvider, ResourceProviderFactory and ValueMap based on the NoSqlAdapter
+* "Transaction management" of Sling CRUD (commit/revert methods) is implemented
+* ValueMap supports String, Integer, Long, Double, Date, Calendar and InputStream/byte\[\] (binary data) and arrays of them. Date/Calendar and binary data is serialized to a string before storing, so the NoSQL databases have not to support them directly.
+* Sends resource notifications via OSGi EventAdmin
+* Provides a "tests" JAR that can be used for integration tests with NoSQL databases to test the own adapter implementation
+* Can be mounted as root provider without any JCR at all
diff --git a/generic/pom.xml b/generic/pom.xml
new file mode 100644
index 0000000..5b596b7
--- /dev/null
+++ b/generic/pom.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>26</version>
+        <relativePath />
+    </parent>
+
+    <artifactId>org.apache.sling.nosql.generic</artifactId>
+    <version>1.1.0</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling NoSQL Generic Resource Provider</name>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</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.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.3.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.5.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.testing.logging-mock</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+</project>
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
new file mode 100644
index 0000000..38eff2b
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Default implementation of {@link NoSqlAdapter}.
+ */
+@ConsumerType
+public abstract class AbstractNoSqlAdapter implements NoSqlAdapter {
+
+    @Override
+    public boolean validPath(String path) {
+        // by default all paths are accepted
+        return true;
+    }
+
+    @Override
+    public Iterator<NoSqlData> query(String query, String language) {
+        // not supported unless it is overwritten explicitly
+        return null;
+    }
+    
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MapConverter.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MapConverter.java
new file mode 100644
index 0000000..a04c8f6
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MapConverter.java
@@ -0,0 +1,87 @@
+/*
+ * 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.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * Transforms NoSqlData maps to a valid form for couchbase JSON document.
+ * All arrays have to be transformed to lists.
+ */
+final class MapConverter {
+
+    private MapConverter() {
+        // static methods only
+    }
+
+    /**
+     * @param map Map with multi-valued arrays
+     * @return Map with multi-valued lists
+     */
+    public static Map<String, Object> mapArrayToList(Map<String, Object> map) {
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            if (entry.getValue().getClass().isArray()) {
+                Class componentType = entry.getValue().getClass().getComponentType();
+                if (componentType == int.class) {
+                    entry.setValue(Arrays.asList(ArrayUtils.toObject((int[]) entry.getValue())));
+                }
+                else if (componentType == long.class) {
+                    entry.setValue(Arrays.asList(ArrayUtils.toObject((long[]) entry.getValue())));
+                }
+                else if (componentType == double.class) {
+                    entry.setValue(Arrays.asList(ArrayUtils.toObject((double[]) entry.getValue())));
+                }
+                else if (componentType == boolean.class) {
+                    entry.setValue(Arrays.asList(ArrayUtils.toObject((boolean[]) entry.getValue())));
+                }
+                else {
+                    entry.setValue(Arrays.asList((Object[]) entry.getValue()));
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * @param map Map with multi-valued lists
+     * @return Map with multi-valued arrays
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> mapListToArray(Map<String, Object> map) {
+        for (Map.Entry<String, Object> entry : map.entrySet()) {
+            if (entry.getValue() instanceof List) {
+                List list = (List) entry.getValue();
+                if (list.size() == 0) {
+                    entry.setValue(null);
+                }
+                else {
+                    Class type = list.get(0).getClass();
+                    entry.setValue(list.toArray((Object[]) Array.newInstance(type, list.size())));
+                }
+            }
+        }
+        return map;
+    }
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
new file mode 100644
index 0000000..319406f
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
@@ -0,0 +1,122 @@
+/*
+ * 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 org.apache.sling.api.resource.LoginException;
+import org.slf4j.Logger;
+
+/**
+ * Wrapper for {@link NoSqlAdapter} that enables logging and time counting for each call.
+ */
+public final class MetricsNoSqlAdapterWrapper implements NoSqlAdapter {
+
+    private final NoSqlAdapter delegate;
+    private final Logger logger;
+
+    public MetricsNoSqlAdapterWrapper(NoSqlAdapter delegate, Logger logger) {
+        this.delegate = delegate;
+        this.logger = logger;
+    }
+
+    public boolean validPath(String path) {
+        return delegate.validPath(path);
+    }
+
+    public NoSqlData get(String path) {
+        Metrics metrics = new Metrics();
+        try {
+            return delegate.get(path);
+        }
+        finally {
+            metrics.finish("get({})", path);
+        }
+    }
+
+    public Iterator<NoSqlData> getChildren(String parentPath) {
+        Metrics metrics = new Metrics();
+        try {
+            return delegate.getChildren(parentPath);
+        }
+        finally {
+            metrics.finish("getChildren({})", parentPath);
+        }
+    }
+
+    public boolean store(NoSqlData data) {
+        Metrics metrics = new Metrics();
+        try {
+            return delegate.store(data);
+        }
+        finally {
+            metrics.finish("store({})", data.getPath());
+        }
+    }
+
+    public boolean deleteRecursive(String path) {
+        Metrics metrics = new Metrics();
+        try {
+            return delegate.deleteRecursive(path);
+        }
+        finally {
+            metrics.finish("deleteRecursive({})", path);
+        }
+    }
+
+    public Iterator<NoSqlData> query(String query, String language) {
+        Metrics metrics = new Metrics();
+        try {
+            return delegate.query(query, language);
+        }
+        finally {
+            metrics.finish("query({})", query);
+        }
+    }
+    
+    @Override
+    public void checkConnection() throws LoginException {
+        delegate.checkConnection();
+    }
+
+    @Override
+    public void createIndexDefinitions() {
+        delegate.createIndexDefinitions();
+    }    
+
+    private class Metrics {
+        
+        private long startTime;
+        
+        public Metrics() {
+            if (logger.isDebugEnabled()) {
+                startTime = System.currentTimeMillis();
+            }
+        }
+        
+        public void finish(String message, Object... data) {
+            if (logger.isDebugEnabled()) {
+                long duration = System.currentTimeMillis() - startTime;
+                logger.debug(message + " - " + duration + "ms", data);
+            }
+        }
+        
+    }
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MultiValueMode.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MultiValueMode.java
new file mode 100644
index 0000000..c0d966d
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/MultiValueMode.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Mode for multi-valued field data in {@link NoSqlData} properties.
+ */
+public enum MultiValueMode {
+
+    /**
+     * Return multi-valued field values as array (default).
+     */
+    ARRAYS,
+    
+    /**
+     * Return multi-valued field values as lists.
+     */
+    LISTS
+    
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
new file mode 100644
index 0000000..fb4d3e9
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
@@ -0,0 +1,93 @@
+/*
+ * 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 org.apache.sling.api.resource.LoginException;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * Adapter for NoSQL databases to be hooked into the Generic NoSQL resource provider.
+ * All implementors should should extend {@link AbstractNoSqlAdapter} to be compatible for future extensions.
+ */
+@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);
+
+    /**
+     * Checks whether the connection to the NoSQL database is possible
+     * @throws LoginException in case of any errors
+     */
+    void checkConnection() throws LoginException;
+
+    /**
+     * Creates index definitions for accessing the NoSQL database.
+     * This is called every time an adapter instances is created. If the indexes are
+     * already present it should do nothing.
+     * It is only called when the {@link #checkConnection()} call succeeds.
+     */
+    void createIndexDefinitions();
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
new file mode 100644
index 0000000..0b52038
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
@@ -0,0 +1,71 @@
+/*
+ * 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, properties, MultiValueMode.ARRAYS);
+    }
+
+    public NoSqlData(String path, Map<String, Object> properties, MultiValueMode multiValueMode) {
+        this.path = path;
+        switch (multiValueMode) {
+            case ARRAYS:
+                this.properties = properties;
+                break;
+            case LISTS:
+                this.properties = MapConverter.mapListToArray(properties);
+                break;
+            default:
+                throw new IllegalArgumentException("Multi value mode not supported: " + multiValueMode);
+        }
+    }
+
+    public String getPath() {
+        return path;
+    }
+    
+    public Map<String, Object> getProperties() {
+        return getProperties(MultiValueMode.ARRAYS);
+    }
+    
+    public Map<String, Object> getProperties(MultiValueMode multiValueMode) {
+        switch (multiValueMode) {
+            case ARRAYS:
+                return properties;
+            case LISTS:
+                return MapConverter.mapArrayToList(properties);
+            default:
+                throw new IllegalArgumentException("Multi value mode not supported: " + multiValueMode);
+        }
+    }
+    
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
new file mode 100644
index 0000000..88474a2
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
@@ -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.
+ */
+@aQute.bnd.annotation.Version("2.0.0")
+package org.apache.sling.nosql.generic.adapter;
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
new file mode 100644
index 0000000..47be2fe
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
@@ -0,0 +1,54 @@
+/*
+ * 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 {
+        NoSqlAdapter adapter = getNoSqlAdapter();
+        adapter.checkConnection();
+        adapter.createIndexDefinitions();
+        return new NoSqlResourceProvider(adapter, getEventAdmin());
+    }
+
+    public final ResourceProvider getAdministrativeResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
+        return getResourceProvider(authenticationInfo);
+    }
+    
+    protected abstract NoSqlAdapter getNoSqlAdapter();
+
+    protected abstract EventAdmin getEventAdmin();
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
new file mode 100644
index 0000000..5431cc1
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
@@ -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();
+    }
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
new file mode 100644
index 0000000..e5ad414
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
@@ -0,0 +1,280 @@
+/*
+ * 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.LinkedHashMap;
+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 static final String ROOT_PATH = "/";
+    
+    private final NoSqlAdapter adapter;
+    private final EventAdmin eventAdmin;
+    private final Map<String, NoSqlData> changedResources = new LinkedHashMap<String, NoSqlData>();
+    private final Set<String> deletedResources = new HashSet<String>();
+    
+    public NoSqlResourceProvider(NoSqlAdapter adapter, EventAdmin eventAdmin) {
+        this.adapter = new ValueMapConvertingNoSqlAdapter(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);
+        }
+        else if (ROOT_PATH.equals(path)) {
+            // root path exists implicitly - bot not yet in nosql store - return a "virtual" resource until something is stored in it
+            NoSqlData rootData = new NoSqlData(ROOT_PATH, new HashMap<String, Object>());
+            return new NoSqlResource(rootData, 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) {
+            if (path.equals(deletedPath) || path.equals(deletedPath + "/")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    
+    // ### WRITE ACCESS ###
+    
+    public Resource create(ResourceResolver resolver, String path, Map<String, Object> properties)
+            throws PersistenceException {
+        if (ROOT_PATH.equals(path) || !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
+        Map<String, Object> writableMap = properties != null ? new HashMap<String, Object>(properties) : new HashMap<String, Object>();
+        NoSqlData data = new NoSqlData(path, NoSqlValueMap.convertForWriteAll(writableMap));
+        changedResources.put(path, data);
+        return new NoSqlResource(data, resolver, this);
+    }
+    
+    public void delete(ResourceResolver resolver, String path) throws PersistenceException {
+        if (ROOT_PATH.equals(path) || !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);
+        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);
+        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);
+        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();
+            }
+        };
+    }
+    
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
new file mode 100644
index 0000000..6f7fcf4
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlValueMap.java
@@ -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.nosql.generic.resource.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Map;
+
+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 == Date.class) {
+            Calendar value = get(name, Calendar.class);
+            if (value != null) {
+                return (T)value.getTime();
+            }
+        }
+        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 == 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 Date) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime((Date)value);
+            value = calendar;
+        }
+        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 != null && !isValidType(value.getClass())) {
+            throw new IllegalArgumentException("Data type not supported for NoSqlValueMap: " + value.getClass());
+        }
+        return value;
+    }
+    
+    static boolean isValidType(Class clazz) {
+        if (clazz.isArray()) {
+            if (clazz.getComponentType() == byte.class) {
+                // byte only supported as array
+                return true;
+            }
+            return isValidType(clazz.getComponentType());
+        }
+        else {
+            return clazz == String.class
+                    || clazz == Integer.class
+                    || clazz == Long.class
+                    || clazz == Double.class
+                    || clazz == Boolean.class
+                    || Calendar.class.isAssignableFrom(clazz);
+        }
+    }
+    
+    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;
+    }
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
new file mode 100644
index 0000000..8af73e6
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 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(StringUtils.removeEnd(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) + "(/.*)?$");
+    }
+    
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
new file mode 100644
index 0000000..37e3c45
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
@@ -0,0 +1,181 @@
+/*
+ * 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.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Special adapter wrapper that converts all Calendar and byte[] values in ValueMap to String values
+ * when passing to the underlying NoSql adapter and back to typed values when reading from it.
+ * This is required because too many implementations access ValueMap without type specifier so
+ * we cannot only rely on the type conversion in the typed get methods of a ValueMap.
+ */
+class ValueMapConvertingNoSqlAdapter implements NoSqlAdapter {
+    
+    private static final String PREFIX_CALENDAR = "{{calendar}}";
+    private static final String PREFIX_BYTE_ARRAY = "{{bytes}}";
+
+    private final NoSqlAdapter delegate;
+    
+    private static final Logger log = LoggerFactory.getLogger(ValueMapConvertingNoSqlAdapter.class);
+
+    public ValueMapConvertingNoSqlAdapter(NoSqlAdapter delegate) {
+        this.delegate = delegate;
+    }
+
+    public boolean validPath(String path) {
+        return delegate.validPath(path);
+    }
+
+    public NoSqlData get(String path) {
+        return deserializeUnsupportedTypes(delegate.get(path));
+    }
+
+    public Iterator<NoSqlData> getChildren(String parentPath) {
+        return deserializeUnsupportedTypes(delegate.getChildren(parentPath));
+    }
+
+    public boolean store(NoSqlData data) {
+        return delegate.store(serializeUnsupportedTypes(data));
+    }
+
+    public boolean deleteRecursive(String path) {
+        return delegate.deleteRecursive(path);
+    }
+
+    public Iterator<NoSqlData> query(String query, String language) {
+        return deserializeUnsupportedTypes(delegate.query(query, language));
+    }
+    
+    private Iterator<NoSqlData> deserializeUnsupportedTypes(final Iterator<NoSqlData> source) {
+        if (source == null) {
+            return null;
+        }
+        return new Iterator<NoSqlData>() {
+            @Override
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+            @Override
+            public NoSqlData next() {
+                return deserializeUnsupportedTypes(source.next());
+            }
+            @Override
+            public void remove() {
+                source.remove();
+            }
+        };
+    }
+    
+    private NoSqlData serializeUnsupportedTypes(NoSqlData data) {
+        if (data == null) {
+            return null;
+        }
+        
+        Map<String,Object> serializedMap = new HashMap<String, Object>();
+        
+        for (Map.Entry<String, Object> entry : data.getProperties().entrySet()) {
+            Object serializedValue = entry.getValue();
+            
+            // Calendar.class
+            if (entry.getValue() instanceof Calendar) {
+                serializedValue = PREFIX_CALENDAR + getISO8601Format().format(((Calendar)entry.getValue()).getTime());
+            }
+            
+            // byte[].class
+            else if (entry.getValue() instanceof byte[]) {
+                serializedValue = PREFIX_BYTE_ARRAY + DatatypeConverter.printBase64Binary((byte[])entry.getValue());
+            }
+            
+            serializedMap.put(entry.getKey(), serializedValue);
+        }
+        
+        return new NoSqlData(data.getPath(), serializedMap);
+    }
+    
+    private NoSqlData deserializeUnsupportedTypes(NoSqlData data) {
+        if (data == null) {
+            return null;
+        }
+        
+        Map<String,Object> deserializedMap = new HashMap<String, Object>();
+
+        for (Map.Entry<String, Object> entry : data.getProperties().entrySet()) {
+            Object deserializedValue = entry.getValue();
+            if (entry.getValue() instanceof String) {
+                String value = (String)entry.getValue();
+                
+                // Calendar.class
+                if (value.indexOf(PREFIX_CALENDAR) == 0) {
+                    String calendarValue = value.substring(PREFIX_CALENDAR.length());
+                    try {
+                        Date date = getISO8601Format().parse((String)calendarValue);
+                        Calendar calendar = Calendar.getInstance();
+                        calendar.setTime(date);
+                        deserializedValue = calendar;
+                    }
+                    catch (ParseException ex) {
+                        log.warn("Unable to parse serialized calendar value: " + entry.getValue(), ex);
+                    }
+                }
+                
+                // byte[].class
+                else if (value.indexOf(PREFIX_BYTE_ARRAY) == 0) {
+                    String byteArrayValue = value.substring(PREFIX_BYTE_ARRAY.length());
+                    deserializedValue = DatatypeConverter.parseBase64Binary(byteArrayValue);
+                }
+                
+            }
+            deserializedMap.put(entry.getKey(), deserializedValue);
+        }
+        
+        return new NoSqlData(data.getPath(), deserializedMap);
+    }
+    
+    @Override
+    public void checkConnection() throws LoginException {
+        delegate.checkConnection();
+    }
+
+    @Override
+    public void createIndexDefinitions() {
+        delegate.createIndexDefinitions();
+    }
+
+    private static DateFormat getISO8601Format() {
+        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
+    }
+
+}
diff --git a/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java b/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
new file mode 100644
index 0000000..3788b29
--- /dev/null
+++ b/generic/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
@@ -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.
+ */
+@aQute.bnd.annotation.Version("1.0.0")
+package org.apache.sling.nosql.generic.resource;
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/adapter/MapConverterTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/adapter/MapConverterTest.java
new file mode 100644
index 0000000..32aa7cd
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/adapter/MapConverterTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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 static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.apache.sling.nosql.generic.adapter.MapConverter;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+public class MapConverterTest {
+
+    @Test
+    public void testMapArrayToList() throws Exception {
+        Map<String, Object> result = MapConverter.mapArrayToList(Maps.newHashMap(ImmutableMap.<String, Object>builder()
+                .put("prop1", "value1")
+                .put("prop2", 2)
+                .put("stringArray", new String[] { "value1", "value2" })
+                .put("integerArray", new Integer[] { 1, 2, 3 })
+                .put("integerArray2", new int[] { 1, 2, 3 })
+                .put("longArray", new long[] { 1L, 2L })
+                .put("doubleArray", new double[] { 1.1d, 1.2d })
+                .put("booleanArray", new boolean[] { true, false })
+                .build()));
+
+        assertEquals("prop1", "value1", result.get("prop1"));
+        assertEquals("prop2", 2, result.get("prop2"));
+        assertEquals("stringArray", ImmutableList.of("value1", "value2"), result.get("stringArray"));
+        assertEquals("integerArray", ImmutableList.of(1, 2, 3), result.get("integerArray"));
+        assertEquals("integerArray2", ImmutableList.of(1, 2, 3), result.get("integerArray2"));
+        assertEquals("longArray", ImmutableList.of(1L, 2L), result.get("longArray"));
+        assertEquals("doubleArray", ImmutableList.of(1.1d, 1.2d), result.get("doubleArray"));
+        assertEquals("booleanArray", ImmutableList.of(true, false), result.get("booleanArray"));
+    }
+
+    @Test
+    public void testMapListToArray() throws Exception {
+        Map<String, Object> result = MapConverter.mapListToArray(Maps.newHashMap(ImmutableMap.<String, Object>builder()
+                .put("prop1", "value1")
+                .put("prop2", 2)
+                .put("stringArray", ImmutableList.of("value1", "value2"))
+                .put("integerArray", ImmutableList.of(1, 2, 3))
+                .put("longArray", ImmutableList.of(1L, 2L))
+                .put("doubleArray", ImmutableList.of(1.1d, 1.2d))
+                .put("booleanArray", ImmutableList.of(true, false))
+                .build()));
+
+        assertEquals("prop1", "value1", result.get("prop1"));
+        assertEquals("prop2", 2, result.get("prop2"));
+        assertArrayEquals("stringArray", new String[] { "value1", "value2" }, (String[]) result.get("stringArray"));
+        assertArrayEquals("integerArray", new Integer[] { 1, 2, 3 }, (Integer[]) result.get("integerArray"));
+        assertArrayEquals("longArray", new Long[] { 1L, 2L }, (Long[]) result.get("longArray"));
+        assertArrayEquals("doubleArray", new Double[] { 1.1d, 1.2d }, (Double[]) result.get("doubleArray"));
+        assertArrayEquals("booleanArray", new Boolean[] { true, false }, (Boolean[]) result.get("booleanArray"));
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java
new file mode 100644
index 0000000..1fead01
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jackrabbit.JcrConstants;
+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.api.resource.ResourceUtil;
+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;
+import com.google.common.collect.Lists;
+
+/**
+ * Test monting NoSqlResourceProvider as root resource provider.
+ */
+public abstract class AbstractNoSqlResourceProviderRootTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext(ResourceResolverType.NONE);
+    
+    protected abstract void registerResourceProviderFactoryAsRoot();
+
+    @Before
+    public void setUp() throws Exception {
+        registerResourceProviderFactoryAsRoot();
+    }
+    
+    @After
+    public void tearDown() {
+        context.resourceResolver().revert();
+    }
+    
+    @Test
+    public void testRoot() {
+        Resource root = context.resourceResolver().getResource("/");
+        assertNotNull(root);
+        assertTrue(root instanceof NoSqlResource);
+    }
+
+    @Test
+    public void testCreatePath() throws PersistenceException {
+        ResourceUtil.getOrCreateResource(context.resourceResolver(), "/test/test1",
+                ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED),
+                JcrConstants.NT_UNSTRUCTURED, true);
+        
+        Resource test = context.resourceResolver().getResource("/test");
+        assertNotNull(test);
+        
+        Resource test1 = context.resourceResolver().getResource("/test/test1");
+        assertNotNull(test1);
+        
+        context.resourceResolver().delete(test);
+    }
+    
+    @Test
+    public void testListChildren_RootNode() throws IOException {
+        Resource testResource = ResourceUtil.getOrCreateResource(context.resourceResolver(), "/test",
+                ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED),
+                JcrConstants.NT_UNSTRUCTURED, true);
+
+        Resource root = context.resourceResolver().getResource("/");
+
+        List<Resource> children = Lists.newArrayList(root.listChildren());
+        assertFalse(children.isEmpty());
+        assertTrue(containsResource(children, testResource));
+
+        children = Lists.newArrayList(root.getChildren());
+        assertFalse(children.isEmpty());
+        assertTrue(containsResource(children, testResource));
+
+        context.resourceResolver().delete(testResource);
+    }
+
+    private boolean containsResource(List<Resource> children, Resource resource) {
+        for (Resource child : children) {
+            if (StringUtils.equals(child.getPath(), resource.getPath())) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    @Test(expected = PersistenceException.class)
+    public void testDeleteRootPath() throws PersistenceException {
+        Resource root = context.resourceResolver().getResource("/");
+        context.resourceResolver().delete(root);
+    }
+
+    @Test
+    public void testUpdateRootPath() throws PersistenceException {
+        Resource root = context.resourceResolver().getResource("/");
+        ModifiableValueMap props = root.adaptTo(ModifiableValueMap.class);
+        props.put("prop1", "value1");
+        context.resourceResolver().commit();
+        
+        root = context.resourceResolver().getResource("/");
+        assertThat(root.getValueMap().get("prop1", String.class), equalTo("value1"));
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
new file mode 100644
index 0000000..fa3a82e
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTest.java
@@ -0,0 +1,217 @@
+/*
+ * 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.isValidType(entry.getValue().getClass()));
+        }
+    }
+
+    @Test
+    public void testPrimaryTypeResourceType() throws PersistenceException {
+        Resource resource = context.resourceResolver().getResource(testRoot().getPath());
+        assertEquals(JcrConstants.NT_UNSTRUCTURED, resource.getResourceType());
+    }
+
+    @Test
+    public void testCreateWithNullMap() throws IOException {
+        Resource resource1 = context.resourceResolver().getResource(testRoot().getPath() + "/node1");
+        context.resourceResolver().create(resource1, "nullMap", null);
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
new file mode 100644
index 0000000..3320806
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderTransactionalTest.java
@@ -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));
+    }
+    
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
new file mode 100644
index 0000000..67efd33
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/resource/impl/PathUtilTest.java
@@ -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());
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
new file mode 100644
index 0000000..6c79168
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderQueryTest.java
@@ -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());
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderRootTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderRootTest.java
new file mode 100644
index 0000000..61cf09a
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderRootTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.nosql.generic.resource.impl.AbstractNoSqlResourceProviderRootTest;
+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 SimpleNoSqlResourceProviderRootTest extends AbstractNoSqlResourceProviderRootTest {
+    
+    @Override
+    protected void registerResourceProviderFactoryAsRoot() {
+        context.registerInjectActivateService(new SimpleNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/")
+                .build());
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
new file mode 100644
index 0000000..aa37032
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTest.java
@@ -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;
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTransactionalTest.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTransactionalTest.java
new file mode 100644
index 0000000..6c8fe12
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlResourceProviderTransactionalTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.assertNull;
+
+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.AbstractNoSqlResourceProviderTransactionalTest;
+import org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class SimpleNoSqlResourceProviderTransactionalTest extends AbstractNoSqlResourceProviderTransactionalTest {
+    
+    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);
+                context.resourceResolver().commit();
+            }
+            catch (PersistenceException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return this.testRoot;
+    }
+
+    @Test
+    public void testGetInvalidPath() {
+        assertNull(context.resourceResolver().getResource(testRoot().getPath() + "/invalid/1"));
+    }
+    
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
new file mode 100644
index 0000000..89da8b1
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
@@ -0,0 +1,128 @@
+/*
+ * 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.provider;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.apache.sling.nosql.generic.resource.impl.PathUtil;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterators;
+
+/**
+ * Stores resource data in a hash map for testing.
+ */
+public class SimpleNoSqlAdapter implements NoSqlAdapter {
+    
+    private final SortedMap<String, Map<String,Object>> store = new TreeMap<String, Map<String,Object>>();
+
+    public boolean validPath(String path) {
+        return !(StringUtils.contains(path, "/invalid/") || StringUtils.endsWith(path, "/invalid"));
+    }
+
+    public NoSqlData get(String path) {
+        Map<String,Object> properties = store.get(path);
+        if (properties != null) {
+            return new NoSqlData(path, properties);
+        }
+        else {
+            return null;
+        }
+    }
+
+    public Iterator<NoSqlData> getChildren(String parentPath) {
+        Iterator<String> keys = store.keySet().iterator();
+        
+        final Pattern childKeyPattern = PathUtil.getChildPathPattern(parentPath);
+        Iterator<String> childKeys = Iterators.filter(keys, new Predicate<String>() {
+            public boolean apply(String path) {
+                return childKeyPattern.matcher(path).matches();
+            }
+        });
+        
+        return Iterators.transform(childKeys, new Function<String, NoSqlData>() {
+            public NoSqlData apply(String path) {
+                return get(path);
+            }
+        });
+    }
+
+    public boolean store(NoSqlData data) {
+        boolean exists = store.containsKey(data.getPath());
+        store.put(data.getPath(), new HashMap<String, Object>(data.getProperties()));
+        return !exists;
+    }
+
+    public boolean deleteRecursive(String path) {
+        boolean deletedAnything = false;
+        final Pattern pathToDeletePattern = PathUtil.getSameOrDescendantPathPattern(path);
+        Iterator<Entry<String, Map<String,Object>>> entries = store.entrySet().iterator();
+        while (entries.hasNext()) {
+            Entry<String, Map<String,Object>> entry = entries.next();
+            if (pathToDeletePattern.matcher(entry.getKey()).matches()) {
+                entries.remove();
+                deletedAnything = true;
+            }
+        }
+        return deletedAnything;
+    }
+
+    public Iterator<NoSqlData> query(String query, String language) {
+        // implement simple dummy query
+        if (StringUtils.equals(language, "simple") && StringUtils.equals(query, "all")) {
+            final Iterator<Entry<String, Map<String,Object>>> entries = store.entrySet().iterator();
+            return new Iterator<NoSqlData>() {
+                public boolean hasNext() {
+                    return entries.hasNext();
+                }
+                public NoSqlData next() {
+                    Entry<String, Map<String,Object>> entry = entries.next();
+                    return new NoSqlData(entry.getKey(), entry.getValue());
+                }
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+        return Collections.<NoSqlData>emptyList().iterator();
+    }
+
+    @Override
+    public void checkConnection() throws LoginException {
+        // nothing to do
+    }
+
+    @Override
+    public void createIndexDefinitions() {
+        // nothing to do
+    }
+
+}
diff --git a/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlResourceProviderFactory.java b/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlResourceProviderFactory.java
new file mode 100644
index 0000000..1a9d09b
--- /dev/null
+++ b/generic/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlResourceProviderFactory.java
@@ -0,0 +1,77 @@
+/*
+ * 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.provider;
+
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.QueriableResourceProvider;
+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.AbstractNoSqlResourceProviderFactory;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * Simple NoSQL resource provider factory based on {@link SimpleNoSqlAdapter} which just stores
+ * the resource data in a hash map.
+ */
+@Component(configurationFactory = true, policy = ConfigurationPolicy.REQUIRE, metatype = true)
+@Service(value = ResourceProviderFactory.class)
+@Properties({
+    @Property(name = ResourceProvider.ROOTS, value = ""),
+    @Property(name = QueriableResourceProvider.LANGUAGES, value = { "simple" })
+})
+public class SimpleNoSqlResourceProviderFactory extends AbstractNoSqlResourceProviderFactory {
+
+    @Reference
+    private EventAdmin eventAdmin;
+    
+    private NoSqlAdapter noSqlAdapter;
+    
+    @Activate
+    protected void activate(final Map<String, Object> props) {
+        noSqlAdapter = new SimpleNoSqlAdapter();
+    }
+    
+    @Override
+    protected NoSqlAdapter getNoSqlAdapter() {
+        return noSqlAdapter;
+    }
+
+    @Override
+    protected EventAdmin getEventAdmin() {
+        return eventAdmin;
+    }
+    
+    protected void bindEventAdmin(EventAdmin eventAdmin) {
+        this.eventAdmin = eventAdmin;
+    }
+
+    protected void unbindEventAdmin(EventAdmin eventAdmin) {
+        this.eventAdmin = null;
+    }
+
+}
diff --git a/generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory.xml b/generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory.xml
new file mode 100644
index 0000000..21f2864
--- /dev/null
+++ b/generic/src/test/resources/OSGI-INF/org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+    <scr:component name="org.apache.sling.nosql.generic.simple.SimpleNoSqlResourceProviderFactory" configuration-policy="require" activate="activate">
+        <implementation class="org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory"/>
+        <service servicefactory="false">
+            <provide interface="org.apache.sling.api.resource.ResourceProviderFactory"/>
+        </service>
+        <property name="provider.roots" value=""/>
+        <property name="provider.query.languages" value="simple"/>
+        <property name="service.vendor" value="The Apache Software Foundation"/>
+        <property name="service.pid" value="org.apache.sling.nosql.generic.simple.provider.SimpleNoSqlResourceProviderFactory"/>
+        <reference name="eventAdmin" interface="org.osgi.service.event.EventAdmin" cardinality="1..1" policy="static" bind="bindEventAdmin" unbind="unbindEventAdmin"/>
+    </scr:component>
+</components>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 06/18: SLING-5151 NoSQL: allow modifying the root resource

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit df91c50010f19ea69e9fae222435a5e226c704f7
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:42:19 2016 +0000

    SLING-5151 NoSQL: allow modifying the root resource
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732078 13f79535-47bb-0310-9956-ffa450edef68
---
 .../nosql/generic/resource/impl/NoSqlResourceProvider.java | 14 +++++---------
 .../impl/AbstractNoSqlResourceProviderRootTest.java        |  7 ++++++-
 2 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
index 2649323..e5ad414 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
@@ -18,7 +18,6 @@
  */
 package org.apache.sling.nosql.generic.resource.impl;
 
-import java.util.Collections;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -53,7 +52,6 @@ import org.osgi.service.event.EventAdmin;
 public class NoSqlResourceProvider implements ResourceProvider, ModifyingResourceProvider, QueriableResourceProvider {
     
     private static final String ROOT_PATH = "/";
-    private static final NoSqlData ROOT_DATA = new NoSqlData(ROOT_PATH, Collections.<String, Object>emptyMap());
     
     private final NoSqlAdapter adapter;
     private final EventAdmin eventAdmin;
@@ -69,10 +67,6 @@ public class NoSqlResourceProvider implements ResourceProvider, ModifyingResourc
     // ### READONLY ACCESS ###
     
     public Resource getResource(ResourceResolver resourceResolver, String path) {
-        if (ROOT_PATH.equals(path)) {
-            return new NoSqlResource(ROOT_DATA, resourceResolver, this);
-        }
-        
         if (!adapter.validPath(path)) {
             return null;
         }
@@ -91,6 +85,11 @@ public class NoSqlResourceProvider implements ResourceProvider, ModifyingResourc
         if (data != null) {
             return new NoSqlResource(data, resourceResolver, this);
         }
+        else if (ROOT_PATH.equals(path)) {
+            // root path exists implicitly - bot not yet in nosql store - return a "virtual" resource until something is stored in it
+            NoSqlData rootData = new NoSqlData(ROOT_PATH, new HashMap<String, Object>());
+            return new NoSqlResource(rootData, resourceResolver, this);
+        }
         return null;
     }
 
@@ -196,9 +195,6 @@ public class NoSqlResourceProvider implements ResourceProvider, ModifyingResourc
                notifyRemoved(path);
             }
             for (NoSqlData item : changedResources.values()) {
-                if (ROOT_PATH.equals(item.getPath())) {
-                    throw new PersistenceException("Unable to store resource at {}" + item.getPath(), null, item.getPath(), null);
-                }
                 boolean created = adapter.store(item);
                 if (created) {
                     notifyAdded(item.getPath());
diff --git a/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java b/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java
index 82d88f0..1fead01 100644
--- a/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java
+++ b/src/test/java/org/apache/sling/nosql/generic/resource/impl/AbstractNoSqlResourceProviderRootTest.java
@@ -18,8 +18,10 @@
  */
 package org.apache.sling.nosql.generic.resource.impl;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
@@ -117,12 +119,15 @@ public abstract class AbstractNoSqlResourceProviderRootTest {
         context.resourceResolver().delete(root);
     }
 
-    @Test(expected = Throwable.class)
+    @Test
     public void testUpdateRootPath() throws PersistenceException {
         Resource root = context.resourceResolver().getResource("/");
         ModifiableValueMap props = root.adaptTo(ModifiableValueMap.class);
         props.put("prop1", "value1");
         context.resourceResolver().commit();
+        
+        root = context.resourceResolver().getResource("/");
+        assertThat(root.getValueMap().get("prop1", String.class), equalTo("value1"));
     }
 
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 15/18: [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit bbd89ef833febd525a249194942931d04a9eed21
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:57:41 2016 +0000

    [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732091 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index f136b8a..81d45fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.1-SNAPSHOT</version>
+    <version>1.1.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 17/18: [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 24581c4c81a67a83d9d0c7f715a46601660f9377
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 12:02:49 2016 +0000

    [maven-release-plugin] prepare release org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732096 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 1b43ce8..f26dec9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.0-SNAPSHOT</version>
+    <version>1.1.0</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 11/18: update package version to 1.0 because we had a major package version update anyway in this release

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit e6d3010d6104cfb5a68790d1494f6e109dbf30c0
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:53:59 2016 +0000

    update package version to 1.0 because we had a major package version update anyway in this release
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732087 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/nosql/generic/resource/package-info.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java b/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
index a804837..3788b29 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Generic NoSQL resource provider implementation.
  */
-@aQute.bnd.annotation.Version("0.5")
+@aQute.bnd.annotation.Version("1.0.0")
 package org.apache.sling.nosql.generic.resource;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 16/18: exclude README.md in rat report

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 6c8333de2d9a11256532fd91e893a4d33db0ee55
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 12:02:10 2016 +0000

    exclude README.md in rat report
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732095 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/pom.xml b/pom.xml
index 81d45fe..1b43ce8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,20 @@
             </plugin>
   
         </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <!-- Extend RAT configuration from parent pom -->
+                    <groupId>org.apache.rat</groupId>
+                    <artifactId>apache-rat-plugin</artifactId>
+                    <configuration>
+                        <excludes combine.children="append">
+                            <exclude>README.md</exclude>
+                        </excludes>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
     </build>
     
     <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 04/18: SLING-5437 The NoSQL providers should throw LoginException if the connection to the NoSQL database can't be established (patch provided by Robert Munteanu)

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 2c43a9f46db4fc5c893bbe31c39c023b2fea8be5
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Tue Jan 19 16:42:12 2016 +0000

    SLING-5437 The NoSQL providers should throw LoginException if the connection to the NoSQL database can't be established (patch provided by Robert Munteanu)
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1725565 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/nosql/generic/adapter/AbstractNoSqlAdapter.java     |  7 +++++++
 .../nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java     |  6 ++++++
 .../org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java  | 11 ++++++++++-
 .../org/apache/sling/nosql/generic/adapter/package-info.java  |  2 +-
 .../resource/AbstractNoSqlResourceProviderFactory.java        |  4 +++-
 .../generic/resource/impl/ValueMapConvertingNoSqlAdapter.java |  6 ++++++
 .../nosql/generic/simple/provider/SimpleNoSqlAdapter.java     |  6 ++++++
 7 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
index 38eff2b..d8672e6 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/AbstractNoSqlAdapter.java
@@ -20,6 +20,8 @@ package org.apache.sling.nosql.generic.adapter;
 
 import java.util.Iterator;
 
+import org.apache.sling.api.resource.LoginException;
+
 import aQute.bnd.annotation.ConsumerType;
 
 /**
@@ -40,4 +42,9 @@ public abstract class AbstractNoSqlAdapter implements NoSqlAdapter {
         return null;
     }
     
+    @Override
+    public void checkConnection() throws LoginException {
+        // not supported unless it is overwritten explicitly
+    }
+
 }
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java b/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
index dfcf7a7..68a8381 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/MetricsNoSqlAdapterWrapper.java
@@ -20,6 +20,7 @@ package org.apache.sling.nosql.generic.adapter;
 
 import java.util.Iterator;
 
+import org.apache.sling.api.resource.LoginException;
 import org.slf4j.Logger;
 
 /**
@@ -89,6 +90,11 @@ public final class MetricsNoSqlAdapterWrapper implements NoSqlAdapter {
         }
     }
     
+    @Override
+    public void checkConnection() throws LoginException {
+        delegate.checkConnection();
+    }
+
     private class Metrics {
         
         private long startTime;
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
index ab3d823..d86cd29 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
@@ -20,6 +20,8 @@ package org.apache.sling.nosql.generic.adapter;
 
 import java.util.Iterator;
 
+import org.apache.sling.api.resource.LoginException;
+
 import aQute.bnd.annotation.ConsumerType;
 
 /**
@@ -73,5 +75,12 @@ public interface NoSqlAdapter {
      * @return Query result or null if query not supported
      */
     Iterator<NoSqlData> query(String query, String language);
-        
+
+    /**
+     * Checks whether the connection to the NoSQL database is possible
+     *
+     * @throws LoginException in case of any errors
+     */
+    void checkConnection() throws LoginException;
+
 }
diff --git a/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java b/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
index aed682e..88474a2 100644
--- a/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
+++ b/src/main/java/org/apache/sling/nosql/generic/adapter/package-info.java
@@ -19,5 +19,5 @@
 /**
  * Adapter for NoSQL resource provider implementation.
  */
-@aQute.bnd.annotation.Version("1.0.0")
+@aQute.bnd.annotation.Version("2.0.0")
 package org.apache.sling.nosql.generic.adapter;
diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java b/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
index 2e56b2b..c1e7811 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
@@ -37,7 +37,9 @@ import aQute.bnd.annotation.ConsumerType;
 public abstract class AbstractNoSqlResourceProviderFactory implements ResourceProviderFactory {
 
     public final ResourceProvider getResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
-        return new NoSqlResourceProvider(getNoSqlAdapter(), getEventAdmin());
+        NoSqlAdapter adapter = getNoSqlAdapter();
+        adapter.checkConnection();
+        return new NoSqlResourceProvider(adapter, getEventAdmin());
     }
 
     public final ResourceProvider getAdministrativeResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
diff --git a/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
index 62974f0..52ef419 100644
--- a/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
+++ b/src/main/java/org/apache/sling/nosql/generic/resource/impl/ValueMapConvertingNoSqlAdapter.java
@@ -30,6 +30,7 @@ import java.util.Map;
 
 import javax.xml.bind.DatatypeConverter;
 
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
 import org.apache.sling.nosql.generic.adapter.NoSqlData;
 import org.slf4j.Logger;
@@ -163,6 +164,11 @@ class ValueMapConvertingNoSqlAdapter implements NoSqlAdapter {
         return new NoSqlData(data.getPath(), deserializedMap);
     }
     
+    @Override
+    public void checkConnection() throws LoginException {
+        delegate.checkConnection();
+    }
+
     private static DateFormat getISO8601Format() {
         return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
     }
diff --git a/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java b/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
index f1743ff..6702e1a 100644
--- a/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
+++ b/src/test/java/org/apache/sling/nosql/generic/simple/provider/SimpleNoSqlAdapter.java
@@ -28,6 +28,7 @@ import java.util.TreeMap;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
 import org.apache.sling.nosql.generic.adapter.NoSqlData;
 import org.apache.sling.nosql.generic.resource.impl.PathUtil;
@@ -114,4 +115,9 @@ public class SimpleNoSqlAdapter implements NoSqlAdapter {
         return Collections.<NoSqlData>emptyList().iterator();
     }
 
+    @Override
+    public void checkConnection() throws LoginException {
+
+    }
+
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 01/18: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit bece24f1788684b391d2809d139262e3a4b42ea3
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Thu Sep 17 21:27:23 2015 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1703697 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 77a6bbd..eedb74b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.0.0</version>
+    <version>1.0.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.0.0</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.0.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.0.0</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 08/18: [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 762996010bd98313eb17c230e2e0a9920e2e72b9
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:51:15 2016 +0000

    [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0@1732083 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 10/18: [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 12436f06db5cbc4d2182a34985f92ff7fc0fbaf6
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:51:49 2016 +0000

    [maven-release-plugin] rollback the release of org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732085 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index f136b8a..81d45fe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.1-SNAPSHOT</version>
+    <version>1.1.0-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 18/18: [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit ea84c17d127577a8b2e4a125cac5ab6515e6b0e0
Merge: f92bfcd 24581c4
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 12:04:51 2016 +0000

    [maven-release-plugin] copy for tag org.apache.sling.nosql.generic-1.1.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0@1732100 13f79535-47bb-0310-9956-ffa450edef68

 generic/README.md                                  |  16 --
 generic/pom.xml                                    | 154 ------------
 .../generic/adapter/AbstractNoSqlAdapter.java      |  43 ----
 .../sling/nosql/generic/adapter/MapConverter.java  |  87 -------
 .../adapter/MetricsNoSqlAdapterWrapper.java        | 122 ---------
 .../nosql/generic/adapter/MultiValueMode.java      |  36 ---
 .../sling/nosql/generic/adapter/NoSqlAdapter.java  |  93 -------
 .../sling/nosql/generic/adapter/NoSqlData.java     |  71 ------
 .../sling/nosql/generic/adapter/package-info.java  |  23 --
 .../AbstractNoSqlResourceProviderFactory.java      |  54 ----
 .../nosql/generic/resource/impl/NoSqlResource.java |  90 -------
 .../resource/impl/NoSqlResourceProvider.java       | 280 ---------------------
 .../nosql/generic/resource/impl/NoSqlValueMap.java | 147 -----------
 .../nosql/generic/resource/impl/PathUtil.java      |  52 ----
 .../impl/ValueMapConvertingNoSqlAdapter.java       | 181 -------------
 .../sling/nosql/generic/resource/package-info.java |  23 --
 .../nosql/generic/adapter/MapConverterTest.java    |  79 ------
 .../AbstractNoSqlResourceProviderRootTest.java     | 133 ----------
 .../impl/AbstractNoSqlResourceProviderTest.java    | 217 ----------------
 ...ractNoSqlResourceProviderTransactionalTest.java | 227 -----------------
 .../nosql/generic/resource/impl/PathUtilTest.java  |  56 -----
 .../SimpleNoSqlResourceProviderQueryTest.java      | 102 --------
 .../SimpleNoSqlResourceProviderRootTest.java       |  39 ---
 .../simple/SimpleNoSqlResourceProviderTest.java    |  64 -----
 ...mpleNoSqlResourceProviderTransactionalTest.java |  73 ------
 .../simple/provider/SimpleNoSqlAdapter.java        | 128 ----------
 .../SimpleNoSqlResourceProviderFactory.java        |  77 ------
 ...provider.SimpleNoSqlResourceProviderFactory.xml |  32 ---
 pom.xml                                            |  14 ++
 .../sling/nosql/generic/resource/package-info.java |   2 +-
 30 files changed, 15 insertions(+), 2700 deletions(-)

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 14/18: [maven-release-plugin] prepare for next development iteration

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit 1cc31d3f11e86c6bdebb89a331cd6dce1c9e137c
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Wed Feb 24 11:54:48 2016 +0000

    [maven-release-plugin] prepare for next development iteration
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1732090 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5b596b7..f136b8a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,15 +28,15 @@
     </parent>
 
     <artifactId>org.apache.sling.nosql.generic</artifactId>
-    <version>1.1.0</version>
+    <version>1.1.1-SNAPSHOT</version>
     <packaging>bundle</packaging>
 
     <name>Apache Sling NoSQL Generic Resource Provider</name>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.nosql.generic-1.1.0</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.nosql.generic-1.1.0</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/contrib/nosql/generic</url>
     </scm>
     
     <properties>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-nosql-generic] 02/18: Update the contrib reactor to parent 25

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.nosql.generic-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-generic.git

commit a9f15320527d3a8298d86def2454d99df88d9d72
Author: Robert Munteanu <ro...@apache.org>
AuthorDate: Mon Oct 5 10:04:15 2015 +0000

    Update the contrib reactor to parent 25
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/nosql/generic@1706781 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index eedb74b..3d92fe5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.sling</groupId>
         <artifactId>sling</artifactId>
-        <version>24</version>
+        <version>25</version>
         <relativePath />
     </parent>
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.