You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2015/05/15 19:01:21 UTC
svn commit: r1679605 - in
/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src:
main/java/org/apache/sling/nosql/generic/adapter/
main/java/org/apache/sling/nosql/generic/resource/
main/java/org/apache/sling/nosql/generic/resource/impl/ test/j...
Author: sseifert
Date: Fri May 15 17:01:21 2015
New Revision: 1679605
URL: http://svn.apache.org/r1679605
Log:
new approach
Removed:
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlModifyingResourceProvider.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlQueriableResourceProvider.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlReadonlyResourceProvider.java
Modified:
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlAdapter.java Fri May 15 17:01:21 2015
@@ -24,6 +24,13 @@ import java.util.Iterator;
* Adapter for NoSQL databases to be hooked into the Generic NoSQL resource provider.
*/
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.
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/adapter/NoSqlData.java Fri May 15 17:01:21 2015
@@ -20,6 +20,9 @@ package org.apache.sling.nosql.generic.a
import java.util.Map;
+/**
+ * Wrapper for properties of a NoSQL document for a given path.
+ */
public final class NoSqlData {
private final String path;
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/AbstractNoSqlResourceProviderFactory.java Fri May 15 17:01:21 2015
@@ -27,6 +27,10 @@ import org.apache.sling.nosql.generic.ad
import org.apache.sling.nosql.generic.resource.impl.NoSqlResourceProvider;
import org.osgi.service.event.EventAdmin;
+/**
+ * Abstract implementation of resource provider factory.
+ * NoSQL resource providers implement this, add their own configuration support and and provide the matching NoSQL adapter implementation.
+ */
public abstract class AbstractNoSqlResourceProviderFactory implements ResourceProviderFactory {
public final ResourceProvider getResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResource.java Fri May 15 17:01:21 2015
@@ -26,8 +26,13 @@ import org.apache.sling.api.resource.Mod
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.ModifiableValueMapDecorator;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.nosql.generic.adapter.NoSqlData;
+/**
+ * Generic implementaiton of a NoSQL database resource.
+ */
public class NoSqlResource extends AbstractResource {
private final NoSqlData data;
@@ -60,13 +65,14 @@ public class NoSqlResource extends Abstr
return metadata;
}
+ @SuppressWarnings("unchecked")
@Override
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
if (type == ValueMap.class || type == Map.class) {
- // TODO: implement value map adaption
+ return (AdapterType)new ValueMapDecorator(data.getProperties());
}
if (type == ModifiableValueMap.class) {
- // TODO: implement value map adaption
+ return (AdapterType)new ModifiableValueMapDecorator(data.getProperties());
}
return super.adaptTo(type);
}
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/NoSqlResourceProvider.java Fri May 15 17:01:21 2015
@@ -18,14 +18,21 @@
*/
package org.apache.sling.nosql.generic.resource.impl;
+import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringUtils;
+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;
@@ -35,61 +42,223 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.nosql.generic.adapter.NoSqlAdapter;
import org.apache.sling.nosql.generic.adapter.NoSqlData;
+import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
+/**
+ * Generic implementation of a NoSQL resource provider.
+ * The mapping to the NoSQL database implementation details is done via the provided {@link NoSqlAdapter}.
+ */
public class NoSqlResourceProvider implements ResourceProvider, ModifyingResourceProvider, QueriableResourceProvider {
- private final NoSqlReadonlyResourceProvider readonlyDelegate;
- private final NoSqlModifyingResourceProvider modifyingDelegate;
- private final NoSqlQueriableResourceProvider queriableDelegate;
-
+ private final NoSqlAdapter adapter;
+ private final EventAdmin eventAdmin;
private final Map<String, NoSqlData> changedResources = new HashMap<String, NoSqlData>();
private final Set<String> deletedResources = new HashSet<String>();
public NoSqlResourceProvider(NoSqlAdapter adapter, EventAdmin eventAdmin) {
- this.readonlyDelegate = new NoSqlReadonlyResourceProvider(adapter, changedResources, deletedResources);
- this.modifyingDelegate = new NoSqlModifyingResourceProvider(adapter, eventAdmin, changedResources, deletedResources);
- this.queriableDelegate = new NoSqlQueriableResourceProvider(adapter);
+ this.adapter = adapter;
+ this.eventAdmin = eventAdmin;
}
+
+ // ### READONLY ACCESS ###
+
public Resource getResource(ResourceResolver resourceResolver, String path) {
- return readonlyDelegate.getResource(resourceResolver, path);
+ if (!adapter.validPath(path)) {
+ return null;
+ }
+ if (this.deletedResources.contains(path)) {
+ return null;
+ }
+ if (this.changedResources.containsKey(path)) {
+ return new NoSqlResource(this.changedResources.get(path), resourceResolver);
+ }
+ NoSqlData data = adapter.get(path);
+ if (data != null) {
+ return new NoSqlResource(data, resourceResolver);
+ }
+ return null;
}
public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
- return readonlyDelegate.getResource(resourceResolver, request, path);
+ return getResource(resourceResolver, path);
}
public Iterator<Resource> listChildren(Resource parent) {
- return readonlyDelegate.listChildren(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()));
+ }
+
+ 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()));
+ }
+ }
+
+ return children.values().iterator();
+ }
+
+ private boolean isDeleted(String path) {
+ for (String deletedPath : deletedResources) {
+ return StringUtils.equals(path, deletedPath) || StringUtils.startsWith(path, deletedPath + "/");
+ }
+ return false;
}
- public Resource create(ResourceResolver resolver, String path, Map<String, Object> properties) throws PersistenceException {
- return modifyingDelegate.create(resolver, path, properties);
+
+ // ### WRITE ACCESS ###
+
+ public Resource create(ResourceResolver resolver, String path, Map<String, Object> properties)
+ throws PersistenceException {
+ if (!adapter.validPath(path)) {
+ throw new PersistenceException("Illegal path - unable to create resource at " + path, null, path, null);
+ }
+
+ // check if already exists
+ boolean deleted = this.deletedResources.remove(path);
+ boolean exists = changedResources.containsKey(path) || this.adapter.get(path) != null;
+ if (!deleted && exists) {
+ throw new PersistenceException("Resource already exists at " + path, null, path, null);
+ }
+
+ // create new resource in changeset
+ NoSqlData data = new NoSqlData(path, properties);
+ changedResources.put(path, data);
+ return new NoSqlResource(data, resolver);
}
-
+
public void delete(ResourceResolver resolver, String path) throws PersistenceException {
- modifyingDelegate.delete(resolver, path);
+ if (!adapter.validPath(path)) {
+ throw new PersistenceException("Unable to delete resource at {}" + path, null, path, null);
+ }
+
+ Pattern pathsToDeletePattern = PathUtil.getSameOrDescendantPathPattern(path);
+
+ // remove all existing path and probably descendant paths from list of deleted paths
+ Iterator<String> deletedResourcesIterator = deletedResources.iterator();
+ while (deletedResourcesIterator.hasNext()) {
+ String deletedPath = deletedResourcesIterator.next();
+ if (pathsToDeletePattern.matcher(deletedPath).matches()) {
+ deletedResourcesIterator.remove();
+ }
+ }
+
+ // remove all changed descendant items from changeset
+ Iterator<Map.Entry<String, NoSqlData>> changeResourcesIterator = changedResources.entrySet().iterator();
+ while (changeResourcesIterator.hasNext()) {
+ Map.Entry<String, NoSqlData> entry = changeResourcesIterator.next();
+ if (pathsToDeletePattern.matcher(entry.getKey()).matches()) {
+ changeResourcesIterator.remove();
+ }
+ }
+
+ // add path to delete
+ deletedResources.add(path);
}
-
+
public void revert(ResourceResolver resolver) {
- modifyingDelegate.revert(resolver);
+ changedResources.clear();
+ deletedResources.clear();
}
-
+
public void commit(ResourceResolver resolver) throws PersistenceException {
- modifyingDelegate.commit(resolver);
+ 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 modifyingDelegate.hasChanges(resolver);
+ return !(changedResources.isEmpty() && deletedResources.isEmpty());
}
-
- public Iterator<Resource> findResources(ResourceResolver resolver, String query, String language) {
- return queriableDelegate.findResources(resolver, query, language);
+
+ private void notifyAdded(String path) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, path);
+ props.put("event.distribute", "");
+ final Event event = new Event(SlingConstants.TOPIC_RESOURCE_ADDED, props);
+ this.eventAdmin.postEvent(event);
+ }
+
+ private void notifyUpdated(String path) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, path);
+ props.put("event.distribute", "");
+ final Event event = new Event(SlingConstants.TOPIC_RESOURCE_CHANGED, props);
+ this.eventAdmin.postEvent(event);
+ }
+
+ private void notifyRemoved(String path) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, path);
+ props.put("event.distribute", "");
+ final Event event = new Event(SlingConstants.TOPIC_RESOURCE_REMOVED, props);
+ this.eventAdmin.postEvent(event);
}
- public Iterator<ValueMap> queryResources(ResourceResolver resolver, String query, String language) {
- return queryResources(resolver, query, language);
+
+ // ### 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);
+ }
+ 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();
+ }
+ };
}
-
+
}
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/main/java/org/apache/sling/nosql/generic/resource/impl/PathUtil.java Fri May 15 17:01:21 2015
@@ -20,6 +20,9 @@ package org.apache.sling.nosql.generic.r
import java.util.regex.Pattern;
+/**
+ * Helper functions for handling paths.
+ */
public final class PathUtil {
private PathUtil() {
Modified: sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java
URL: http://svn.apache.org/viewvc/sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java?rev=1679605&r1=1679604&r2=1679605&view=diff
==============================================================================
--- sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java (original)
+++ sling/whiteboard/sseifert/SLING-4381_nosql/nosql-generic/src/test/java/org/apache/sling/nosql/generic/simple/SimpleNoSqlAdapter.java Fri May 15 17:01:21 2015
@@ -18,12 +18,14 @@
*/
package org.apache.sling.nosql.generic.simple;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
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;
@@ -36,6 +38,10 @@ public class SimpleNoSqlAdapter implemen
private final Map<String, Map<String,Object>> store = new HashMap<String, Map<String,Object>>();
+ public boolean validPath(String path) {
+ return true;
+ }
+
public NoSqlData get(String path) {
Map<String,Object> properties = store.get(path);
if (properties != null) {
@@ -84,8 +90,23 @@ public class SimpleNoSqlAdapter implemen
}
public Iterator<NoSqlData> query(String query, String language) {
- // not supported
- return null;
+ // 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();
}
}