You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ch...@apache.org on 2014/06/03 12:41:50 UTC

svn commit: r1599472 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/ oak-pojosr/ oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/ oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/

Author: chetanm
Date: Tue Jun  3 10:41:49 2014
New Revision: 1599472

URL: http://svn.apache.org/r1599472
Log:
OAK-1708 - extend DocumentNodeStoreService to support RDBPersistence

Added support for referencing the DataSource via OSGi service and also added relevant testcase in pojosr module

Added:
    jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
    jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
    jackrabbit/oak/trunk/oak-pojosr/pom.xml
    jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy
    jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1599472&r1=1599471&r2=1599472&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java Tue Jun  3 10:41:49 2014
@@ -516,7 +516,9 @@ public class DocumentMK implements Micro
          */
         public Builder setRDBConnection(DataSource ds) {
             this.documentStore = new RDBDocumentStore(ds, this);
-            this.blobStore = new RDBBlobStore(ds);
+            if(this.blobStore == null) {
+                this.blobStore = new RDBBlobStore(ds);
+            }
             return this;
         }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1599472&r1=1599471&r2=1599472&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java Tue Jun  3 10:41:49 2014
@@ -18,8 +18,6 @@
  */
 package org.apache.jackrabbit.oak.plugins.document;
 
-import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -30,6 +28,10 @@ import java.util.concurrent.TimeUnit;
 
 import javax.sql.DataSource;
 
+import com.mongodb.DB;
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoClientURI;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.ConfigurationPolicy;
@@ -65,10 +67,11 @@ import org.osgi.service.component.Compon
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.mongodb.DB;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoClientOptions;
-import com.mongodb.MongoClientURI;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toBoolean;
+import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toInteger;
+import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toLong;
+import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.registerMBean;
 
 /**
  * The OSGi service to start/stop a DocumentNodeStore instance.
@@ -118,8 +121,25 @@ public class DocumentNodeStoreService {
      */
     public static final String CUSTOM_BLOB_STORE = "customBlobStore";
 
+    /**
+     * Boolean value indicating a different DataSource has to be used for
+     * BlobStore
+     */
+    public static final String CUSTOM_BLOB_DATA_SOURCE = "customBlobDataSource";
+
     private static final long MB = 1024 * 1024;
 
+    private static enum DocumentStoreType {
+        MONGO, RDB;
+
+        static DocumentStoreType fromString(String type) {
+            if (type == null) {
+                return MONGO;
+            }
+            return valueOf(type.toUpperCase());
+        }
+    }
+
     private final Logger log = LoggerFactory.getLogger(this.getClass());
 
     private ServiceRegistration reg;
@@ -130,6 +150,18 @@ public class DocumentNodeStoreService {
             policy = ReferencePolicy.DYNAMIC)
     private volatile BlobStore blobStore;
 
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY,
+            policy = ReferencePolicy.DYNAMIC,
+            target = "(datasource.name=oak)"
+    )
+    private volatile DataSource dataSource;
+
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY,
+            policy = ReferencePolicy.DYNAMIC,
+            target = "(datasource.name=oak)"
+    )
+    private volatile DataSource blobDataSource;
+
     private DocumentMK mk;
     private ObserverTracker observerTracker;
     private ComponentContext context;
@@ -155,39 +187,54 @@ public class DocumentNodeStoreService {
     private static final long DEFAULT_MAX_REPLICATION_LAG = TimeUnit.HOURS.toSeconds(6);
     public static final String PROP_REPLICATION_LAG = "maxReplicationLagInSecs";
     private long maxReplicationLagInSecs = DEFAULT_MAX_REPLICATION_LAG;
+
+    /**
+     * Specifies the type of DocumentStore MONGO, RDB
+     */
+    public static final String PROP_DS_TYPE = "documentStoreType";
+    private DocumentStoreType documentStoreType;
+
     private boolean customBlobStore;
+    private boolean customBlobDataSource;
 
     @Activate
     protected void activate(ComponentContext context, Map<String, ?> config) throws Exception {
         this.context = context;
-        this.whiteboard = new OsgiWhiteboard(context.getBundleContext());
-        this.executor = new WhiteboardExecutor();
+        whiteboard = new OsgiWhiteboard(context.getBundleContext());
+        executor = new WhiteboardExecutor();
         executor.start(whiteboard);
-        this.maxReplicationLagInSecs = PropertiesUtil.toLong(config.get(PROP_REPLICATION_LAG),
-                DEFAULT_MAX_REPLICATION_LAG);
-        this.customBlobStore = PropertiesUtil.toBoolean(prop(CUSTOM_BLOB_STORE), false);
+        maxReplicationLagInSecs = toLong(config.get(PROP_REPLICATION_LAG), DEFAULT_MAX_REPLICATION_LAG);
+        customBlobStore = toBoolean(prop(CUSTOM_BLOB_STORE), false);
+        customBlobDataSource = toBoolean(prop(CUSTOM_BLOB_DATA_SOURCE), false);
+        documentStoreType = DocumentStoreType.fromString(PropertiesUtil.toString(config.get(PROP_DS_TYPE), "MONGO"));
+
+        modified(config);
+        registerNodeStoreIfPossible();
+    }
 
-        if (blobStore == null && customBlobStore) {
+    private void registerNodeStoreIfPossible() throws IOException {
+        if (context == null) {
+            log.info("Component still not activated. Ignoring the initialization call");
+        } else if (customBlobStore && blobStore == null) {
             log.info("BlobStore use enabled. DocumentNodeStoreService would be initialized when "
                     + "BlobStore would be available");
+        } else if (documentStoreType == DocumentStoreType.RDB
+                && (dataSource == null || (customBlobDataSource && blobDataSource == null))) {
+            log.info("DataSource use enabled. DocumentNodeStoreService would be initialized when "
+                    + "DataSource would be available");
         } else {
             registerNodeStore();
         }
-        modified(config);
     }
 
-    protected void registerNodeStore() throws IOException {
-        if (context == null) {
-            log.info("Component still not activated. Ignoring the initialization call");
-            return;
-        }
+    private void registerNodeStore() throws IOException {
         String uri = PropertiesUtil.toString(prop(PROP_URI, FWK_PROP_URI), DEFAULT_URI);
         String db = PropertiesUtil.toString(prop(PROP_DB, FWK_PROP_DB), DEFAULT_DB);
 
-        int offHeapCache = PropertiesUtil.toInteger(prop(PROP_OFF_HEAP_CACHE), DEFAULT_OFF_HEAP_CACHE);
-        int cacheSize = PropertiesUtil.toInteger(prop(PROP_CACHE), DEFAULT_CACHE);
-        int changesSize = PropertiesUtil.toInteger(prop(PROP_CHANGES_SIZE), DEFAULT_CHANGES_SIZE);
-        boolean useMK = PropertiesUtil.toBoolean(context.getProperties().get(PROP_USE_MK), false);
+        int offHeapCache = toInteger(prop(PROP_OFF_HEAP_CACHE), DEFAULT_OFF_HEAP_CACHE);
+        int cacheSize = toInteger(prop(PROP_CACHE), DEFAULT_CACHE);
+        int changesSize = toInteger(prop(PROP_CHANGES_SIZE), DEFAULT_CHANGES_SIZE);
+        boolean useMK = toBoolean(context.getProperties().get(PROP_USE_MK), false);
 
         DocumentMK.Builder mkBuilder =
                 new DocumentMK.Builder().
@@ -195,7 +242,9 @@ public class DocumentNodeStoreService {
                 offHeapCacheSize(offHeapCache * MB);
 
         //Set blobstore before setting the DB
-        if (blobStore != null && customBlobStore) {
+        if (customBlobStore) {
+            checkNotNull(blobStore, "Use of custom BlobStore enabled via  [%s] but blobStore reference not " +
+                    "initialized", CUSTOM_BLOB_STORE);
             mkBuilder.setBlobStore(blobStore);
         }
 
@@ -234,6 +283,17 @@ public class DocumentNodeStoreService {
                 mkBuilder.setRDBConnection(ds, dsbs);
                 log.info("Connected to datasources {} {}", ds, dsbs);
             }
+        } else if (documentStoreType == DocumentStoreType.RDB){
+            checkNotNull(dataSource, "DataStore type set [%s] but DataSource reference not initialized", PROP_DS_TYPE);
+            if(customBlobDataSource){
+                checkNotNull(blobDataSource, "DataStore type set [%s] and BlobStore is configured to use different " +
+                        "DataSource via [%s] but BlobDataSource reference not initialized", PROP_DS_TYPE, CUSTOM_BLOB_DATA_SOURCE);
+                mkBuilder.setRDBConnection(dataSource, blobDataSource);
+                log.info("Connected to datasources {} {}", dataSource, blobDataSource);
+            } else {
+                mkBuilder.setRDBConnection(dataSource);
+                log.info("Connected to datasource {}", dataSource);
+            }
         } else {
             MongoClientOptions.Builder builder = MongoConnection.getDefaultBuilder();
             MongoClientURI mongoURI = new MongoClientURI(uri, builder);
@@ -286,8 +346,8 @@ public class DocumentNodeStoreService {
      */
     @Modified
     protected void modified(Map<String, ?> config){
-        versionGcMaxAgeInSecs = PropertiesUtil.toLong(config.get(PROP_VER_GC_MAX_AGE), DEFAULT_VER_GC_MAX_AGE);
-        blobGcMaxAgeInSecs = PropertiesUtil.toLong(config.get(PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE);
+        versionGcMaxAgeInSecs = toLong(config.get(PROP_VER_GC_MAX_AGE), DEFAULT_VER_GC_MAX_AGE);
+        blobGcMaxAgeInSecs = toLong(config.get(PROP_BLOB_GC_MAX_AGE), DEFAULT_BLOB_GC_MAX_AGE);
     }
 
     @Deactivate
@@ -303,7 +363,7 @@ public class DocumentNodeStoreService {
     protected void bindBlobStore(BlobStore blobStore) throws IOException {
         log.info("Initializing DocumentNodeStore with BlobStore [{}]", blobStore);
         this.blobStore = blobStore;
-        registerNodeStore();
+        registerNodeStoreIfPossible();
     }
 
     @SuppressWarnings("UnusedDeclaration")
@@ -312,6 +372,30 @@ public class DocumentNodeStoreService {
         unregisterNodeStore();
     }
 
+    @SuppressWarnings("UnusedDeclaration")
+    protected void bindDataSource(DataSource dataSource) throws IOException {
+        this.dataSource = dataSource;
+        registerNodeStoreIfPossible();
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected void unbindDataSource(DataSource dataSource) {
+        this.dataSource = null;
+        unregisterNodeStore();
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected void bindBlobDataSource(DataSource dataSource) throws IOException {
+        this.blobDataSource = dataSource;
+        registerNodeStoreIfPossible();
+    }
+
+    @SuppressWarnings("UnusedDeclaration")
+    protected void unbindBlobDataSource(DataSource dataSource) {
+        this.blobDataSource = null;
+        unregisterNodeStore();
+    }
+
     private void unregisterNodeStore() {
         for (Registration r : registrations) {
             r.unregister();
@@ -399,7 +483,7 @@ public class DocumentNodeStoreService {
     }
 
     private void registerLastRevRecoveryJob(final DocumentNodeStore nodeStore) {
-        long leaseTime = PropertiesUtil.toLong(context.getProperties().get(PROP_REV_RECOVERY_INTERVAL),
+        long leaseTime = toLong(context.getProperties().get(PROP_REV_RECOVERY_INTERVAL),
                 ClusterNodeInfo.DEFAULT_LEASE_DURATION_MILLIS);
         Runnable recoverJob = new Runnable() {
             @Override

Modified: jackrabbit/oak/trunk/oak-pojosr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/pom.xml?rev=1599472&r1=1599471&r2=1599472&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-pojosr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-pojosr/pom.xml Tue Jun  3 10:41:49 2014
@@ -178,6 +178,23 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>com.h2database</groupId>
+      <artifactId>h2</artifactId>
+      <version>${h2.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>4.3.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.gmongo</groupId>
+      <artifactId>gmongo</artifactId>
+      <version>1.1</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.codehaus.groovy</groupId>
       <artifactId>groovy-all</artifactId>
       <version>${groovy.version}</version>

Modified: jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy?rev=1599472&r1=1599471&r2=1599472&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy (original)
+++ jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/AbstractRepositoryFactoryTest.groovy Tue Jun  3 10:41:49 2014
@@ -27,19 +27,18 @@ import org.junit.After
 import org.junit.Before
 import org.osgi.framework.ServiceReference
 import org.osgi.service.cm.ConfigurationAdmin
+import org.osgi.util.tracker.ServiceTracker
 
-import javax.jcr.Repository
-import javax.jcr.RepositoryException
-import javax.jcr.RepositoryFactory
-import javax.jcr.Session
-import javax.jcr.SimpleCredentials
+import javax.jcr.*
+import java.util.concurrent.TimeUnit
 import java.util.concurrent.atomic.AtomicInteger
 
 import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_HOME
 import static org.apache.jackrabbit.oak.run.osgi.OakOSGiRepositoryFactory.REPOSITORY_STARTUP_TIMEOUT
 
-abstract class AbstractRepositoryFactoryTest {
-    static AtomicInteger counter = new AtomicInteger()
+abstract class AbstractRepositoryFactoryTest{
+    static final int SVC_WAIT_TIME = Integer.getInteger("pojosr.waitTime", 10)
+    static final AtomicInteger counter = new AtomicInteger()
     Map config
     File workDir
     Repository repository
@@ -47,7 +46,7 @@ abstract class AbstractRepositoryFactory
 
     @Before
     void setUp() {
-        workDir = new File("target", "repotest-${counter}-${System.currentTimeMillis()}");
+        workDir = new File("target", "repotest-${counter.incrementAndGet()}-${System.currentTimeMillis()}");
         config = [
                 (REPOSITORY_HOME): workDir.absolutePath,
                 (REPOSITORY_STARTUP_TIMEOUT) : 2
@@ -76,6 +75,14 @@ abstract class AbstractRepositoryFactory
         return (T) registry.getService(sr)
     }
 
+    protected <T> T getServiceWithWait(Class<T> clazz) {
+        ServiceTracker st = new ServiceTracker(getRegistry().bundleContext, clazz.name, null)
+        st.open()
+        T sr = (T) st.waitForService(TimeUnit.SECONDS.toMillis(SVC_WAIT_TIME))
+        assert sr , "No service found for ${clazz.name}"
+        return sr
+    }
+
     protected File getResource(String path){
         File file = new File(FilenameUtils.concat(getBaseDir(), "src/test/resources/$path"))
         assert file.exists() : "No file found at ${file.absolutePath}"

Added: jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy?rev=1599472&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy (added)
+++ jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/DocumentNodeStoreConfigTest.groovy Tue Jun  3 10:41:49 2014
@@ -0,0 +1,202 @@
+/*
+ * 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.jackrabbit.oak.run.osgi
+
+import de.kalpatec.pojosr.framework.launch.PojoServiceRegistry
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore
+import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection
+import org.apache.jackrabbit.oak.spi.blob.BlobStore
+import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore
+import org.apache.jackrabbit.oak.spi.state.NodeStore
+import org.h2.jdbcx.JdbcDataSource
+import org.junit.After
+import org.junit.Test
+
+import javax.sql.DataSource
+import java.sql.Connection
+import java.sql.ResultSet
+
+import static org.junit.Assume.assumeNotNull
+
+class DocumentNodeStoreConfigTest extends AbstractRepositoryFactoryTest {
+    private PojoServiceRegistry registry
+    private MongoConnection mongoConn = MongoUtils.getConnection()
+
+    @Test
+    public void testRDBDocumentStore() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config)
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB;DB_CLOSE_DELAY=-1")
+        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        createConfig([
+                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
+                        documentStoreType: 'RDB'
+                ]
+        ])
+
+        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
+
+        //3. Check that DS contains tables from both RDBBlobStore and RDBDocumentStore
+        assert getExistingTables(ds).containsAll(['NODES', 'DATASTORE_META'])
+    }
+
+    @Test
+    public void testRDBDocumentStore_CustomBlobDataSource() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config)
+
+        //1. Register the DataSource as a service
+        DataSource ds1 = createDS("jdbc:h2:mem:testRDB1;DB_CLOSE_DELAY=-1")
+        registry.registerService(DataSource.class.name, ds1, ['datasource.name': 'oak'] as Hashtable)
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        createConfig([
+                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
+                        documentStoreType      : 'RDB',
+                        customBlobDataSource   : true,
+                        'blobDataSource.target': '(datasource.name=oak-blob)',
+                ]
+        ])
+
+        DataSource ds2 = createDS("jdbc:h2:mem:testRDB2;DB_CLOSE_DELAY=-1")
+        registry.registerService(DataSource.class.name, ds2, ['datasource.name': 'oak-blob'] as Hashtable)
+
+        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
+
+        //3. Check that DS contains tables from RDBBlobStore and RDBDocumentStore
+        //in there respective DataStores
+        List<String> ds1Tables = getExistingTables(ds1)
+        List<String> ds2Tables = getExistingTables(ds2)
+
+        //DS1 should contain RDBDocumentStore tables
+        assert ds1Tables.contains('NODES')
+        assert !ds1Tables.contains('DATASTORE_META')
+
+        //DS2 should contain only RDBBlobStore tables
+        assert !ds2Tables.contains('NODES')
+        assert ds2Tables.contains('DATASTORE_META')
+    }
+
+    @Test
+    public void testRDBDocumentStore_CustomBlobStore() throws Exception {
+        registry = repositoryFactory.initializeServiceRegistry(config)
+
+        //1. Register the DataSource as a service
+        DataSource ds = createDS("jdbc:h2:mem:testRDB3;DB_CLOSE_DELAY=-1")
+        registry.registerService(DataSource.class.name, ds, ['datasource.name': 'oak'] as Hashtable)
+
+        //2. Create config for DocumentNodeStore with RDB enabled
+        createConfig([
+                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
+                        documentStoreType: 'RDB',
+                        customBlobStore  : true
+                ]
+        ])
+
+        registry.registerService(BlobStore.class.name, new MemoryBlobStore(), null)
+
+        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
+
+        //3. Check that DS contains tables only from both RDBDocumentStore
+        List<String> dsTables = getExistingTables(ds)
+
+        //DS1 should contain RDBDocumentStore tables
+        assert dsTables.contains('NODES')
+        assert !dsTables.contains('DATASTORE_META')
+    }
+
+    @Test
+    public void testMongoDocumentStore_CustomBlobStore() throws Exception {
+        assumeNotNull(mongoConn)
+
+        registry = repositoryFactory.initializeServiceRegistry(config)
+        createConfig([
+                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
+                        mongouri       : MongoUtils.mongoURI,
+                        db             : MongoUtils.mongoDB,
+                        customBlobStore: true
+                ]
+        ])
+
+        registry.registerService(BlobStore.class.name, new MemoryBlobStore(), null)
+
+        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
+
+        Collection<String> colNames = getCollectionNames()
+        assert colNames.containsAll(['NODES'])
+        assert !colNames.contains(['BLOBS'])
+    }
+
+    @Test
+    public void testMongoDocumentStore() throws Exception {
+        assumeNotNull(mongoConn)
+
+        registry = repositoryFactory.initializeServiceRegistry(config)
+        createConfig([
+                'org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService': [
+                        mongouri: MongoUtils.mongoURI,
+                        db      : MongoUtils.mongoDB
+                ]
+        ])
+
+        DocumentNodeStore ns = getServiceWithWait(NodeStore.class)
+
+        Collection<String> colNames = getCollectionNames()
+        assert colNames.containsAll(['NODES', "BLOBS"])
+    }
+
+    @Override
+    protected PojoServiceRegistry getRegistry() {
+        return registry
+    }
+
+    @After
+    public void tearDown() {
+        if (mongoConn) {
+            MongoUtils.dropCollections(mongoConn.DB)
+        }
+    }
+
+    private Collection<String> getCollectionNames() {
+        return mongoConn.DB.getCollectionNames().collect { it.toUpperCase() }
+    }
+
+    private List<String> getExistingTables(DataSource ds) {
+        Connection con = ds.connection
+        List<String> existing = []
+        try {
+            ResultSet rs = con.metaData.getTables(null, null, "%", null)
+            while (rs.next()) {
+                existing << rs.toRowResult()['TABLE_NAME'].toUpperCase()
+            }
+        } finally {
+            con.close()
+        }
+        return existing
+    }
+
+    private DataSource createDS(String url) {
+        DataSource ds = new JdbcDataSource()
+        ds.url = url
+        return ds
+    }
+}

Modified: jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy?rev=1599472&r1=1599471&r2=1599472&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy (original)
+++ jackrabbit/oak/trunk/oak-pojosr/src/test/groovy/org/apache/jackrabbit/oak/run/osgi/NodeStoreConfigTest.groovy Tue Jun  3 10:41:49 2014
@@ -26,9 +26,6 @@ import org.apache.jackrabbit.oak.spi.blo
 import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore
 import org.apache.jackrabbit.oak.spi.state.NodeStore
 import org.junit.Test
-import org.osgi.util.tracker.ServiceTracker
-
-import java.util.concurrent.TimeUnit
 
 class NodeStoreConfigTest extends  AbstractRepositoryFactoryTest{
     private PojoServiceRegistry registry
@@ -41,10 +38,7 @@ class NodeStoreConfigTest extends  Abstr
                 'org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService' : [:]
         ])
 
-        ServiceTracker st = new ServiceTracker(registry.bundleContext, NodeStore.class.name, null)
-        st.open()
-
-        SegmentNodeStoreService ns = st.waitForService(TimeUnit.SECONDS.toMillis(10)) as SegmentNodeStoreService
+        SegmentNodeStoreService ns = getServiceWithWait(NodeStore.class)
         //NodeStore is of type SegmentNodeStoreService
         SegmentStore segStore = ns.getSegmentStore()
         assert segStore.blobStore == null , "BlobStore should not be picked up unless 'customBlobStore " +

Added: jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java?rev=1599472&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java (added)
+++ jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java Tue Jun  3 10:41:49 2014
@@ -0,0 +1,94 @@
+/*
+ * 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.jackrabbit.oak.run.osgi;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+
+/**
+ * A utility class to get a {@link MongoConnection} to a local mongo instance
+ * and clean a test database.
+ */
+public class MongoUtils {
+
+    protected static final String HOST =
+            System.getProperty("mongo.host", "127.0.0.1");
+
+    protected static final int PORT =
+            Integer.getInteger("mongo.port", 27017);
+
+    protected static final String DB =
+            System.getProperty("mongo.db", "MongoMKDB");
+
+    protected static Exception exception;
+
+    /**
+     * Get a connection if available. If not available, null is returned.
+     *
+     * @return the connection or null
+     */
+    public static MongoConnection getConnection() {
+        return getConnection(DB);
+    }
+
+    public static String getMongoURI(){
+        return String.format("mongodb://%s:%s", HOST, PORT);
+    }
+
+    public static String getMongoDB(){
+        return DB;
+    }
+
+    /**
+     * Get a connection if available. If not available, null is returned.
+     *
+     * @param dbName the database name
+     * @return the connection or null
+     */
+    public static MongoConnection getConnection(String dbName) {
+        if (exception != null) {
+            return null;
+        }
+        MongoConnection mongoConnection = null;
+        try {
+            mongoConnection = new MongoConnection(HOST, PORT, dbName);
+            mongoConnection.getDB().command(new BasicDBObject("ping", 1));
+            // dropCollections(mongoConnection.getDB());
+        } catch (Exception e) {
+            exception = e;
+            mongoConnection = null;
+        }
+        return mongoConnection;
+    }
+
+    /**
+     * Drop all user defined collections. System collections are not dropped.
+     *
+     * @param db the connection
+     */
+    public static void dropCollections(DB db) {
+        for (String name : db.getCollectionNames()) {
+            if (!name.startsWith("system.")) {
+                db.getCollection(name).drop();
+            }
+        }
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-pojosr/src/test/java/org/apache/jackrabbit/oak/run/osgi/MongoUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native