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>.