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/10/18 23:26:17 UTC

[sling-org-apache-sling-nosql-mongodb-resourceprovider] 02/27: SLING-5024 Sling NoSQL Resource Provider for MongoDB (based on nosql.generic)

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

rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-nosql-mongodb-resourceprovider.git

commit da9cdca3a5dba06c88f77425e9488ca1cbdebe37
Author: Stefan Seifert <ss...@apache.org>
AuthorDate: Mon Sep 14 21:22:00 2015 +0000

    SLING-5024 Sling NoSQL Resource Provider for MongoDB (based on nosql.generic)
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1703063 13f79535-47bb-0310-9956-ffa450edef68
---
 .../resourceprovider/impl/MongoDBNoSqlAdapter.java | 109 ++++++++++++++++++++
 .../impl/MongoDBNoSqlResourceProviderFactory.java  | 113 +++++++++++++++++++++
 .../MongoDBNoSqlResourceProviderIT.java            |  69 +++++++++++++
 .../MongoDBNoSqlResourceProviderRootIT.java        |  42 ++++++++
 ...ongoDBNoSqlResourceProviderTransactionalIT.java |  69 +++++++++++++
 5 files changed, 402 insertions(+)

diff --git a/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlAdapter.java b/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlAdapter.java
new file mode 100644
index 0000000..fe509f2
--- /dev/null
+++ b/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlAdapter.java
@@ -0,0 +1,109 @@
+/*
+ * 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.mongodb.resourceprovider.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.sling.nosql.generic.adapter.AbstractNoSqlAdapter;
+import org.apache.sling.nosql.generic.adapter.MultiValueMode;
+import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.bson.Document;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoCursor;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.Filters;
+import com.mongodb.client.model.UpdateOptions;
+import com.mongodb.client.result.DeleteResult;
+import com.mongodb.client.result.UpdateResult;
+
+/**
+ * {@link org.apache.sling.nosql.generic.adapter.NoSqlAdapter} implementation for MongoDB.
+ */
+public final class MongoDBNoSqlAdapter extends AbstractNoSqlAdapter {
+    
+    private static final String ID_PROPERTY = "_id";
+    private static final String DATA_PROPERTY = "_data";
+    
+    private final MongoCollection<Document> collection;
+    
+    /**
+     * @param mongoClient MongoDB client
+     * @param database MongoDB database
+     * @param collection MongoDB collection
+     */
+    public MongoDBNoSqlAdapter(MongoClient mongoClient, String database, String collection) {
+        MongoDatabase db = mongoClient.getDatabase(database);
+        this.collection = db.getCollection(collection);
+    }
+
+    @Override
+    public NoSqlData get(String path) {
+        Document wrapper = collection.find(Filters.eq(ID_PROPERTY, path)).first();
+        if (wrapper == null) {
+            return null;
+        }
+        else {
+            return new NoSqlData(path, wrapper.get(DATA_PROPERTY, Document.class), MultiValueMode.LISTS);
+        }
+    }
+
+    @Override
+    public Iterator<NoSqlData> getChildren(String parentPath) {
+        List<NoSqlData> children = new ArrayList<>();
+        Pattern directChildren = Pattern.compile("^" + Pattern.quote(parentPath) + "/[^/]+$");
+        FindIterable<Document> result = collection.find(Filters.regex(ID_PROPERTY, directChildren));
+        try (MongoCursor<Document> wrappers = result.iterator()) {
+            while (wrappers.hasNext()) {
+                Document wrapper = wrappers.next();
+                String path = wrapper.get(ID_PROPERTY, String.class);
+                Document data = wrapper.get(DATA_PROPERTY, Document.class);
+                children.add(new NoSqlData(path, data, MultiValueMode.LISTS));
+            }
+        }
+        return children.iterator();
+    }
+
+    @Override
+    public boolean store(NoSqlData data) {
+        Document wrapper = new Document();
+        wrapper.put(ID_PROPERTY, data.getPath());
+        wrapper.put(DATA_PROPERTY, new Document(data.getProperties(MultiValueMode.LISTS)));
+        
+        UpdateResult result = collection.replaceOne(Filters.eq(ID_PROPERTY, data.getPath()), wrapper, new UpdateOptions().upsert(true));
+        
+        // return true if a new entry was inserted, false if an existing was replaced
+        return (result.getMatchedCount() == 0);
+    }
+
+    @Override
+    public boolean deleteRecursive(String path) {        
+        Pattern decendantsAndSelf = Pattern.compile("^" + Pattern.quote(path) + "(/.+)?$");
+        DeleteResult result = collection.deleteMany(Filters.regex(ID_PROPERTY, decendantsAndSelf));
+        
+        // return true if any document was deleted
+        return result.getDeletedCount() > 0;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlResourceProviderFactory.java b/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlResourceProviderFactory.java
new file mode 100644
index 0000000..cf697f0
--- /dev/null
+++ b/src/main/java/org/apache/sling/nosql/mongodb/resourceprovider/impl/MongoDBNoSqlResourceProviderFactory.java
@@ -0,0 +1,113 @@
+/*
+ * 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.mongodb.resourceprovider.impl;
+
+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.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.nosql.generic.adapter.MetricsNoSqlAdapterWrapper;
+import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
+import org.apache.sling.nosql.generic.resource.AbstractNoSqlResourceProviderFactory;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.EventAdmin;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.MongoClient;
+
+import aQute.bnd.annotation.component.Deactivate;
+
+/**
+ * {@link ResourceProviderFactory} implementation that uses MongoDB as persistence.
+ */
+@Component(immediate = true, metatype = true,
+    name="org.apache.sling.nosql.mongodb.resourceprovider.MongoDBNoSqlResourceProviderFactory.factory.config",
+    label = "Apache Sling NoSQL MongoDB Resource Provider Factory", 
+    description = "Defines a resource provider factory with MongoDB persistence.", 
+    configurationFactory = true, policy = ConfigurationPolicy.REQUIRE)
+@Service(value = ResourceProviderFactory.class)
+@Property(name = "webconsole.configurationFactory.nameHint", 
+    value = "Root paths: {" + MongoDBNoSqlResourceProviderFactory.PROVIDER_ROOTS_PROPERTY + "}")
+public final class MongoDBNoSqlResourceProviderFactory extends AbstractNoSqlResourceProviderFactory {
+
+    @Property(label = "Root paths", description = "Root paths for resource provider.", cardinality = Integer.MAX_VALUE)
+    static final String PROVIDER_ROOTS_PROPERTY = ResourceProvider.ROOTS;
+    
+    @Property(label = "Connection String",
+            description = "MongoDB connection String. Example: 'localhost:27017,localhost:27018,localhost:27019'",
+            value = MongoDBNoSqlResourceProviderFactory.CONNECTION_STRING_DEFAULT)
+    static final String CONNECTION_STRING_PROPERTY = "connectionString";
+    private static final String CONNECTION_STRING_DEFAULT = "localhost:27017";
+    
+    @Property(label = "Database",
+            description = "MongoDB database to store resource data in.",
+            value = MongoDBNoSqlResourceProviderFactory.DATABASE_DEFAULT)
+    static final String DATABASE_PROPERTY = "database";
+    private static final String DATABASE_DEFAULT = "sling";
+    
+    @Property(label = "Collection",
+            description = "MongoDB collection to store resource data in.",
+            value = MongoDBNoSqlResourceProviderFactory.COLLECTION_DEFAULT)
+    static final String COLLECTION_PROPERTY = "collection";
+    private static final String COLLECTION_DEFAULT = "resources";
+    
+    @Reference
+    private EventAdmin eventAdmin;
+
+    private MongoClient mongoClient;
+    private NoSqlAdapter noSqlAdapter;
+
+    @Activate
+    private void activate(ComponentContext componentContext, Map<String, Object> config) {
+        String connectionString = PropertiesUtil.toString(config.get(CONNECTION_STRING_PROPERTY), CONNECTION_STRING_DEFAULT);
+        String database = PropertiesUtil.toString(config.get(DATABASE_PROPERTY), DATABASE_DEFAULT);
+        String collection = PropertiesUtil.toString(config.get(COLLECTION_PROPERTY), COLLECTION_DEFAULT);
+        
+        mongoClient = new MongoClient(connectionString);
+        NoSqlAdapter mongodbAdapter = new MongoDBNoSqlAdapter(mongoClient, database, collection);
+        
+        // enable call logging and metrics for {@link MongoDBNoSqlAdapter}
+        noSqlAdapter = new MetricsNoSqlAdapterWrapper(mongodbAdapter, LoggerFactory.getLogger(MongoDBNoSqlAdapter.class));
+    }
+    
+    @Deactivate
+    private void deactivate() {
+        if (mongoClient != null) {
+            mongoClient.close();
+        }
+    }
+
+    @Override
+    protected NoSqlAdapter getNoSqlAdapter() {
+        return noSqlAdapter;
+    }
+
+    @Override
+    protected EventAdmin getEventAdmin() {
+        return eventAdmin;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderIT.java b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderIT.java
new file mode 100644
index 0000000..4126f54
--- /dev/null
+++ b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderIT.java
@@ -0,0 +1,69 @@
+/*
+ * 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.mongodb.resourceprovider.integration;
+
+import java.util.UUID;
+
+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.mongodb.resourceprovider.impl.MongoDBNoSqlResourceProviderFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class MongoDBNoSqlResourceProviderIT extends AbstractNoSqlResourceProviderTest {
+
+    private Resource testRoot;
+
+    @Override
+    protected void registerResourceProviderFactory() {
+        context.registerInjectActivateService(new MongoDBNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/test")
+                .put("connectionString", System.getProperty("connectionString", "localhost:27017"))
+                .put("database", System.getProperty("database", "sling"))
+                .put("collection", System.getProperty("collection", "resources"))
+                .build());
+    }
+
+    @Override
+    protected Resource testRoot() {
+        if (this.testRoot == null) {
+            try {
+                Resource root = context.resourceResolver().getResource("/");
+                Resource providerRoot = root.getChild("test");
+                if (providerRoot == null) {
+                    providerRoot = context.resourceResolver().create(root, "test",
+                            ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED));
+                }
+                this.testRoot = context.resourceResolver().create(providerRoot, UUID.randomUUID().toString(),
+                        ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED));
+            }
+            catch (PersistenceException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return this.testRoot;
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderRootIT.java b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderRootIT.java
new file mode 100644
index 0000000..4a28224
--- /dev/null
+++ b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderRootIT.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.nosql.mongodb.resourceprovider.integration;
+
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.nosql.generic.resource.impl.AbstractNoSqlResourceProviderRootTest;
+import org.apache.sling.nosql.mongodb.resourceprovider.impl.MongoDBNoSqlResourceProviderFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class MongoDBNoSqlResourceProviderRootIT extends AbstractNoSqlResourceProviderRootTest {
+    
+    @Override
+    protected void registerResourceProviderFactoryAsRoot() {
+        context.registerInjectActivateService(new MongoDBNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/")
+                .put("connectionString", System.getProperty("connectionString", "localhost:27017"))
+                .put("database", System.getProperty("database", "sling"))
+                .put("collection", System.getProperty("collection", "resources"))
+                .build());
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderTransactionalIT.java b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderTransactionalIT.java
new file mode 100644
index 0000000..9325496
--- /dev/null
+++ b/src/test/java/org/apache/sling/nosql/mongodb/resourceprovider/integration/MongoDBNoSqlResourceProviderTransactionalIT.java
@@ -0,0 +1,69 @@
+/*
+ * 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.mongodb.resourceprovider.integration;
+
+import java.util.UUID;
+
+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.mongodb.resourceprovider.impl.MongoDBNoSqlResourceProviderFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test basic ResourceResolver and ValueMap with different data types.
+ */
+public class MongoDBNoSqlResourceProviderTransactionalIT extends AbstractNoSqlResourceProviderTransactionalTest {
+
+    private Resource testRoot;
+
+    @Override
+    protected void registerResourceProviderFactory() {
+        context.registerInjectActivateService(new MongoDBNoSqlResourceProviderFactory(), ImmutableMap.<String, Object>builder()
+                .put(ResourceProvider.ROOTS, "/test")
+                .put("connectionString", System.getProperty("connectionString", "localhost:27017"))
+                .put("database", System.getProperty("database", "sling"))
+                .put("collection", System.getProperty("collection", "resources"))
+                .build());
+    }
+
+    @Override
+    protected Resource testRoot() {
+        if (this.testRoot == null) {
+            try {
+                Resource root = context.resourceResolver().getResource("/");
+                Resource providerRoot = root.getChild("test");
+                if (providerRoot == null) {
+                    providerRoot = context.resourceResolver().create(root,"test",
+                            ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED));
+                }
+                this.testRoot = context.resourceResolver().create(providerRoot, UUID.randomUUID().toString(),
+                        ImmutableMap.<String, Object>of(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED));
+            }
+            catch (PersistenceException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return this.testRoot;
+    }
+
+}

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