You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:58:18 UTC
[sling-org-apache-sling-resourcecollection] 01/20: SLING-2853
Commit patch 4 by Amit Gupta (Thanks alot)
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.resourcecollection-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourcecollection.git
commit 15a8f7caa51ce8808f1e1f59f052fdc4b084367b
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Mon May 6 07:30:46 2013 +0000
SLING-2853 Commit patch 4 by Amit Gupta (Thanks alot)
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/collection@1479479 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 155 +++++++++++
.../resource/collection/ResourceCollection.java | 130 +++++++++
.../collection/ResourceCollectionManager.java | 93 +++++++
.../impl/ResourceCollectionAdapterFactory.java | 103 +++++++
.../collection/impl/ResourceCollectionImpl.java | 309 +++++++++++++++++++++
.../impl/ResourceCollectionManagerImpl.java | 138 +++++++++
.../impl/util/ResourceCollectionUtil.java | 49 ++++
.../impl/ResourceCollectionImplTest.java | 221 +++++++++++++++
.../resource/collection/test/MockResource.java | 104 +++++++
.../collection/test/MockResourceResolver.java | 249 +++++++++++++++++
10 files changed, 1551 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100755
index 0000000..2b066af
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <!-- ======================================================================= -->
+ <!-- P A R E N T P R O J E C T -->
+ <!-- ======================================================================= -->
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>15</version>
+ <relativePath>../../../parent/pom.xml</relativePath>
+ </parent>
+
+ <!-- ======================================================================= -->
+ <!-- P R O J E C T -->
+ <!-- ======================================================================= -->
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.resourcecollection</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Resource Collection API</name>
+ <description>
+ The Apache sling resource collection bundle provides an api to create collections of resources.
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/resourcecollection</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/resourcecollection</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/bundles/resourcecollection</url>
+ </scm>
+
+ <!-- ======================================================================= -->
+ <!-- B U I L D -->
+ <!-- ======================================================================= -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>maven-sling-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+
+ </plugin>
+ </plugins>
+ </build>
+
+ <!-- ======================================================================= -->
+ <!-- D E P E N D E N C I E S -->
+ <!-- ======================================================================= -->
+ <dependencies>
+
+
+ <!-- sling -->
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.api</artifactId>
+ <version>2.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.resource</artifactId>
+ <version>2.2.6</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- OSGI -->
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <!-- Felix -->
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.scr.annotations</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Testing -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit-addons</groupId>
+ <artifactId>junit-addons</artifactId>
+ <version>1.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.framework</artifactId>
+ <version>3.0.8</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.4</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/src/main/java/org/apache/sling/resource/collection/ResourceCollection.java b/src/main/java/org/apache/sling/resource/collection/ResourceCollection.java
new file mode 100755
index 0000000..b1a4f6f
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/ResourceCollection.java
@@ -0,0 +1,130 @@
+/*
+ * 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.resource.collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+
+/**
+ * ResourceCollection is an ordered collection of resources. Actual resources are not stored inside the collection.
+ *
+ * Each entry in a collection is represented as a resource, which contain a reference to original resource
+ * and it can have additional properties i.e. creationDate.
+ */
+public interface ResourceCollection {
+
+ /**
+ * Sling resource type for resource representing a </code>ResourceCollection<code>
+ */
+ public static final String RESOURCE_TYPE = "sling/collection";
+
+ /**
+ * Returns name of the collection.
+ *
+ * @return name of the collection.
+ */
+ public String getName();
+
+ /**
+ * Returns path of the collection.
+ *
+ * @return path of the collection.
+ */
+ public String getPath();
+
+ /**
+ * Returns an iterator over resources referred in the collection in the specified order.
+ *
+ * @return iterator over resources referred in collection.
+ */
+ Iterator<Resource> getResources();
+
+ /**
+ * Returns additional properties for a particular resource in Collection entry.
+ *
+ * @return properties of the Collection entry as <code>ModifiableValueMap</code>, returns null if entry found.
+ */
+ ModifiableValueMap getProperties(Resource resource);
+
+ /**
+ * Returns true if resource reference is part of the collection.
+ *
+ * @param resource resource to be checked
+ * @return true if resource is part of the collection.
+ * false otherwise
+ */
+ boolean contains(Resource resource);
+
+
+ /**
+ * Creates a new entry in the collection at the last position and add a reference to resource
+ * in the entry.
+ * Changes are transient & have to be saved by calling resolver.commit()
+ *
+ * @param resource resource to be added
+ * @param properties The additional properties to be stored with the collection entry (can be null).
+ * @return true if addition of resource to collection was successful or
+ * false if collection already contained the resource or resource is null.
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ boolean add(Resource resource, Map<String, Object> properties) throws PersistenceException;
+
+ /**
+ * Creates a new entry in the collection at the last position and add a reference to resource
+ * in the entry.
+ * Changes are transient & have to be saved by calling resolver.commit()
+ *
+ * @param resource resource to be added
+ * @return true if addition of resource to collection was successful or
+ * false if collection already contained the resource or resource is null.
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ boolean add(Resource resource) throws PersistenceException;
+
+
+ /**
+ * Removes a entry of resource from collection & returns true if successful.
+ * Changes are transient & have to be saved by calling resolver.commit()
+ *
+ * @param resource resource reference to be removed
+ * @return true if resource reference was successfully removed from the collection.
+ * false if not removed/not present
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ boolean remove(Resource resource) throws PersistenceException;
+
+ /**
+ * This method inserts the referenced resource <code>srcResource</code>
+ * into the collection entry at the position immediately before the referenced resource <code>destResource</code>.
+ *
+ * To insert the referenced resource into last position, <code>destResource</code> can be null.
+ *
+ * @param srcResource Referenced resource that needs to be moved in the order
+ * @param destResource Referenced resource before which the <code>srcResource</code> will be placed.
+ */
+ void orderBefore(Resource srcResource, Resource destResource);
+}
diff --git a/src/main/java/org/apache/sling/resource/collection/ResourceCollectionManager.java b/src/main/java/org/apache/sling/resource/collection/ResourceCollectionManager.java
new file mode 100755
index 0000000..290e6d7
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/ResourceCollectionManager.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.sling.resource.collection;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+
+/**
+ * The <code>ResourceCollectionManager<code> defines the API to get, create and delete
+ * resource collection {@link org.apache.sling.resource.collection.ResourceCollection}.
+ *
+ * A ResourceCollectionManager instance can be retrieved by adapting ResourceResolver.
+ */
+public interface ResourceCollectionManager {
+
+ /**
+ * This method returns a resource collection for the given <code>resource</code>
+ * that represents a {@link ResourceCollection}.
+ *
+ * It returns null if given resource is not a collection
+ *
+ * @param resource resource that represents a collection
+ * @return The {@link org.apache.sling.resource.collection.ResourceCollection} representing the collection.
+ *
+ */
+ ResourceCollection getCollection(Resource resource);
+
+
+ /**
+ * This method creates a resource collection with a given name under the <code>parentResource</code>.
+ * The changes are transient and have to be saved by resourceResolver.commit()
+ *
+ * @param parentResource parent resource where collection needs to be created.
+ * @param name The name for collection.
+ *
+ * @return The {@link org.apache.sling.resource.collection.ResourceCollection} representing the created collection.
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ ResourceCollection createCollection(Resource parentResource, String name) throws PersistenceException;
+
+ /**
+ * This method creates a resource collection with a given name under the <code>parentResource</code>.
+ * The changes are transient and have to be saved by resourceResolver.commit()
+ *
+ * @param parentResource parent resource where collection needs to be created.
+ * @param name The name for collection.
+ * @param properties The additional data for resource collection
+ *
+ * @return The {@link org.apache.sling.resource.collection.ResourceCollection} representing the created collection.
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ ResourceCollection createCollection(Resource parentResource, String name, Map<String,Object> properties) throws PersistenceException;
+
+ /**
+ * Removes the {@link org.apache.sling.resource.collection.ResourceCollection} corresponding to the collection represented by
+ * <code>resource</code>.
+ * The changes are transient and have to be saved by resourceResolver.commit()
+ *
+ * @param resource resource representing a collection to be deleted.
+ * @return <code>true</code> if the collection was successfully removed.
+ *
+ * @throws {@link PersistenceException} if the operation fails
+ */
+ boolean deleteCollection(Resource resource) throws PersistenceException;
+
+ /**
+ * Returns the {@link ResourceResolver} from which this has been retrieved/adapted.
+ */
+ ResourceResolver getResourceResolver();
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionAdapterFactory.java b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionAdapterFactory.java
new file mode 100755
index 0000000..c7a2790
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionAdapterFactory.java
@@ -0,0 +1,103 @@
+/*
+ * 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.resource.collection.impl;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.adapter.AdapterFactory;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resource.collection.ResourceCollection;
+import org.apache.sling.resource.collection.ResourceCollectionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AdapterFactory that adapts Resources to: {@link ResourceCollection}
+ * And ResourceResolver to: {@link ResourceCollectionManager)
+ */
+@Component(metatype = false)
+@Service
+@Property(name = "service.description", value = "Collection Adapter Factory")
+public class ResourceCollectionAdapterFactory implements AdapterFactory {
+
+ private static final Logger log = LoggerFactory.getLogger(ResourceCollectionAdapterFactory.class);
+
+ private static final Class<ResourceCollection> COLLECTION_CLASS = ResourceCollection.class;
+
+ private static final Class<ResourceCollectionManager> COLLECTION_MGR_CLASS = ResourceCollectionManager.class;
+
+ @Property(name = "adapters")
+ public static final String[] ADAPTER_CLASSES = {
+ COLLECTION_CLASS.getName(), COLLECTION_MGR_CLASS.getName()
+
+ };
+
+ @Property(name = "adaptables")
+ public static final String[] ADAPTABLE_CLASSES = {
+ Resource.class.getName(), ResourceResolver.class.getName()
+
+ };
+
+ // ---------- AdapterFactory -----------------------------------------------
+
+ public <AdapterType> AdapterType getAdapter(Object adaptable,
+ Class<AdapterType> type) {
+ if (adaptable instanceof Resource) {
+ return getAdapter((Resource) adaptable, type);
+ } else if (adaptable instanceof ResourceResolver) {
+ return getAdapter((ResourceResolver) adaptable, type);
+ } else {
+ log.warn("Unable to handle adaptable {}",
+ adaptable.getClass().getName());
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private <AdapterType> AdapterType getAdapter(Resource resource,
+ Class<AdapterType> type) {
+ if (resource != null) {
+ if (type == COLLECTION_CLASS) {
+ if (resource.isResourceType(ResourceCollection.RESOURCE_TYPE)) {
+ return (AdapterType) new ResourceCollectionImpl(resource);
+ }
+ }
+ log.debug("Unable to adapt resource of {} to type {}",
+ resource.getResourceType(), type.getName());
+
+ }
+ log.debug("Unable to adapt null resource to type {}", type.getName());
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <AdapterType> AdapterType getAdapter(ResourceResolver resolver,
+ Class<AdapterType> type) {
+ if (COLLECTION_MGR_CLASS == type) {
+ return (AdapterType) new ResourceCollectionManagerImpl(resolver);
+ } else {
+ log.warn("Unable to adapt resolver to requested type {}",
+ type.getName());
+ return null;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionImpl.java b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionImpl.java
new file mode 100755
index 0000000..ccf88a0
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionImpl.java
@@ -0,0 +1,309 @@
+/*
+ * 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.resource.collection.impl;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.jcr.resource.JcrResourceConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.sling.resource.collection.ResourceCollection;
+import org.apache.sling.resource.collection.impl.util.ResourceCollectionUtil;
+
+/**
+ * Implements <code>ResourceCollection</code>
+ *
+ */
+public class ResourceCollectionImpl implements
+ ResourceCollection {
+
+ private static final Logger log = LoggerFactory.getLogger(ResourceCollectionImpl.class);
+
+ /**
+ * Defines the resource type property
+ */
+ private static final String RESOURCE_TYPE = JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY;
+
+ /**
+ * underlying resource
+ */
+ private final Resource resource;
+
+ /**
+ * The resource resolver in use by the resource.
+ */
+ private final ResourceResolver resolver;
+
+ private final Resource membersResource;
+
+ private static final String REF_PROPERTY = "sling:resource";
+
+ private static final String MEMBERS_NODE_NAME = "members";
+
+ private static final String REFERENCES_PROP = "sling:references";
+
+ /**
+ * Creates a new collection from the given resource
+ *
+ * @param resource the resource
+ */
+ public ResourceCollectionImpl(Resource resource) {
+ this.resource = resource;
+ resolver = resource.getResourceResolver();
+ membersResource = resource.getChild(MEMBERS_NODE_NAME);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getName() {
+ return resource.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPath() {
+ return resource.getPath();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(Resource res, Map<String, Object> properties) throws PersistenceException {
+ if (res != null && !contains(res)) {
+ ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class);
+ String[] order = vm.get(REFERENCES_PROP, new String[]{});
+
+ order = (String[]) ArrayUtils.add(order, res.getPath());
+ vm.put(REFERENCES_PROP, order);
+
+ if (properties == null) {
+ properties = new HashMap<String, Object>();
+ }
+ properties.put(REF_PROPERTY, res.getPath());
+ resolver.create(
+ membersResource,
+ ResourceCollectionUtil.createUniqueChildName(membersResource,
+ res.getName()), properties);
+ log.debug("added member to resource {} to collection {}",
+ new String[] { res.getPath(), resource.getPath() });
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean add(Resource res) throws PersistenceException {
+ if (res != null && !contains(res)) {
+ ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class);
+ String[] order = vm.get(REFERENCES_PROP, new String[]{});
+
+ order = (String[]) ArrayUtils.add(order, res.getPath());
+ vm.put(REFERENCES_PROP, order);
+
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(REF_PROPERTY, res.getPath());
+ resolver.create(
+ membersResource,
+ ResourceCollectionUtil.createUniqueChildName(membersResource,
+ res.getName()), properties);
+ log.debug("added member to resource {} to collection {}",
+ new String[] { res.getPath(), resource.getPath() });
+ return true;
+ }
+
+ return false;
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Iterator<Resource> getResources() {
+
+ ValueMap vm = membersResource.adaptTo(ValueMap.class);
+ String[] references = vm.get(REFERENCES_PROP, new String[]{});
+ List<Resource> resources = new ArrayList<Resource>();
+
+ for (String path:references) {
+ Resource resource = resolver.getResource(path);
+ if (resource != null){
+ resources.add(resource);
+ }
+ }
+
+ return resources.iterator();
+ }
+
+ /**
+ * Returns the sling resource type on content node of collection
+ *
+ * @param
+ * @return <code>sling:resourceType</code> for the collection resource
+ */
+ public String getType() {
+ return resource.getResourceType();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean contains(Resource res) {
+ if (res != null) {
+ ValueMap vm = membersResource.adaptTo(ValueMap.class);
+ String[] order = vm.get(REFERENCES_PROP, new String[]{});
+
+ int index = ArrayUtils.indexOf(order, res.getPath(), 0);
+
+ return index >= 0 ? true: false;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean remove(Resource res) throws PersistenceException {
+ //remove the resource
+ Resource tobeRemovedRes = findRes(res);
+ if (tobeRemovedRes == null) {
+ return false;
+ }
+ resolver.delete(tobeRemovedRes);
+ //remove from order array
+ ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class);
+ String[] order = vm.get(REFERENCES_PROP, new String[]{});
+
+ int index = ArrayUtils.indexOf(order, res.getPath(), 0);
+
+ order = (String[]) ArrayUtils.remove(order, index);
+ vm.put(REFERENCES_PROP, order);
+
+ return true;
+ }
+
+ /**
+ * Sets the sling resource type on content node of collection
+ *
+ * @param type <code>sling:resourceType</code> to be set on the content node
+ * @return
+ */
+ public void setType(String type) throws PersistenceException {
+ ModifiableValueMap mvp = resource.adaptTo(ModifiableValueMap.class);
+ mvp.put(RESOURCE_TYPE, type);
+ }
+
+ private Resource findRes(Resource res) {
+ if (res != null) {
+ String resName = res.getName();
+ if (membersResource.getChild(resName) != null
+ && (res.getPath()).equals(ResourceUtil.getValueMap(
+ membersResource.getChild(resName)).get(REF_PROPERTY, "")))
+ return membersResource.getChild(resName);
+ // handle multiple res with same name but different paths
+ Iterator<Resource> children = membersResource.listChildren();
+ while (children.hasNext()) {
+ Resource r = children.next();
+ if (ResourceUtil.getValueMap(r).get(REF_PROPERTY, "").equals(
+ res.getPath())) return r;
+ }
+ }
+ return null;
+ }
+
+ public void orderBefore(Resource srcResource, Resource destResource) {
+ if (srcResource == null) {
+ throw new IllegalArgumentException("Source Resource can not be null");
+ }
+ ModifiableValueMap vm = membersResource.adaptTo(ModifiableValueMap.class);
+ String[] order = vm.get(REFERENCES_PROP, new String[]{});
+ String srcPath = srcResource.getPath();
+ int srcIndex = ArrayUtils.indexOf(order, srcPath);
+ if (srcIndex < 0) {
+ log.warn("Collection ordering failed, as there is no resource {} in collection {} for destResource",
+ srcPath, getPath());
+ return ;
+ }
+ if (destResource == null) {
+ //add it to the end.
+ order = (String[]) ArrayUtils.remove(order, srcIndex);
+ order = (String[]) ArrayUtils.add(order, srcPath);
+ } else {
+ String destPath = destResource.getPath();
+
+ if (destPath.equals(srcPath)) {
+ String message = MessageFormat.format("Collection ordering failed, as source {} and destination {} can not be same",
+ srcPath, destPath);
+ log.error(message);
+ throw new IllegalArgumentException(message);
+ }
+
+ int destIndex = ArrayUtils.indexOf(order, destPath);
+
+ if (destIndex < 0) {
+ log.warn("Collection ordering failed, as there is no resource {} in collection {} for destResource",
+ destPath, getPath());
+ return;
+ }
+
+ order = (String[]) ArrayUtils.remove(order, srcIndex);
+ if (srcIndex < destIndex) { //recalculate dest index
+ destIndex = ArrayUtils.indexOf(order, destPath);
+ }
+ order = (String[]) ArrayUtils.add(order, destIndex, srcPath);
+ }
+
+ vm.put(REFERENCES_PROP, order);
+ }
+
+ public ModifiableValueMap getProperties(Resource resource) {
+ Iterator<Resource> entries = membersResource.listChildren();
+ while (entries.hasNext()) {
+ Resource entry = entries.next();
+ String path = ResourceUtil.getValueMap(entry).get(
+ REF_PROPERTY, "");
+
+ if (resource.getPath().equals(path)) {
+ return entry.adaptTo(ModifiableValueMap.class);
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionManagerImpl.java b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionManagerImpl.java
new file mode 100755
index 0000000..450bc7c
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/impl/ResourceCollectionManagerImpl.java
@@ -0,0 +1,138 @@
+/*
+ * 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.resource.collection.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.JcrResourceConstants;
+import org.apache.sling.resource.collection.ResourceCollection;
+import org.apache.sling.resource.collection.ResourceCollectionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * Implements <code>ResourceCollectionManger</code> interface. And provides
+ * create, delete, get apis for ResourceCollection.
+ *
+ * A ResourceCollectionManager instance can be retrieved by adapting ResourceResolver.
+ */
+public class ResourceCollectionManagerImpl implements ResourceCollectionManager {
+
+ private static final Logger log = LoggerFactory.getLogger(ResourceCollectionManager.class);
+
+ private final ResourceResolver resolver;
+
+ public ResourceCollectionManagerImpl(ResourceResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ResourceCollection getCollection(Resource resource) {
+ if (resource != null) {
+ if (resource.isResourceType(ResourceCollection.RESOURCE_TYPE)) {
+ return new ResourceCollectionImpl(resource);
+ }
+ } else {
+ throw new IllegalArgumentException("resource can not be null");
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ResourceCollection createCollection(Resource parentResource, String name)
+ throws PersistenceException {
+ return createCollection(parentResource, name, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ResourceCollection createCollection(Resource parentResource, String name,
+ Map<String, Object> properties) throws PersistenceException {
+
+ if (parentResource != null) {
+ String fullPath = parentResource.getPath() + name;
+
+ if (resolver.getResource(fullPath) != null) {
+ throw new IllegalArgumentException("invalid path, " + fullPath
+ + "resource already exists");
+ }
+
+ if (properties == null) {
+ properties = new HashMap<String, Object>();
+ }
+
+ if (properties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY) != null
+ && !ResourceCollection.RESOURCE_TYPE.equals(properties.get(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY))) {
+ properties.put(
+ JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY,
+ ResourceCollection.RESOURCE_TYPE);
+ } else {
+ properties.put(
+ JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY,
+ ResourceCollection.RESOURCE_TYPE);
+ }
+ Resource collectionRes = resolver.create(parentResource, name, properties);
+ resolver.create(collectionRes, "members", null);
+ log.debug("collection {} created", fullPath);
+
+ return new ResourceCollectionImpl(
+ resolver.getResource(collectionRes.getPath()));
+ } else {
+ log.error("parent resource can not be null");
+ throw new IllegalArgumentException("parent resource can not be null ");
+ }
+
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws PersistenceException
+ */
+ public boolean deleteCollection(Resource resource)
+ throws PersistenceException {
+ if (resource != null) {
+ log.debug("collection {} deleted", resource.getPath());
+ resolver.delete(resource);
+ return true;
+ } else {
+ throw new IllegalArgumentException("resource can not be null");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ResourceResolver getResourceResolver() {
+ return resolver;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/resource/collection/impl/util/ResourceCollectionUtil.java b/src/main/java/org/apache/sling/resource/collection/impl/util/ResourceCollectionUtil.java
new file mode 100755
index 0000000..2f56494
--- /dev/null
+++ b/src/main/java/org/apache/sling/resource/collection/impl/util/ResourceCollectionUtil.java
@@ -0,0 +1,49 @@
+/*
+ * 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.resource.collection.impl.util;
+
+
+import org.apache.sling.api.resource.Resource;
+
+public class ResourceCollectionUtil {
+
+ /**
+ * Create a unique name for a child of the <code>resource</code>. Generates a unique name and test if child
+ * already exists. If name is already existing, iterate until a unique one is found
+ *
+ * @param resource parent resource
+ * @param name the name to check
+ * @return a unique label string
+ */
+ public static String createUniqueChildName(Resource resource, String name) {
+ if (resource.getChild(name)!=null) {
+ // leaf node already exists, create new unique name
+ String leafNodeName;
+ int i = 0;
+ do {
+ leafNodeName = name + String.valueOf(i);
+ i++;
+ } while (resource.getChild(leafNodeName)!=null);
+ return leafNodeName;
+ }
+ return name;
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/resource/collection/impl/ResourceCollectionImplTest.java b/src/test/java/org/apache/sling/resource/collection/impl/ResourceCollectionImplTest.java
new file mode 100755
index 0000000..f37c207
--- /dev/null
+++ b/src/test/java/org/apache/sling/resource/collection/impl/ResourceCollectionImplTest.java
@@ -0,0 +1,221 @@
+package org.apache.sling.resource.collection.impl;
+
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import junit.framework.Assert;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.jcr.resource.JcrResourceConstants;
+import org.apache.sling.resource.collection.ResourceCollection;
+import org.apache.sling.resource.collection.ResourceCollectionManager;
+import org.apache.sling.resource.collection.test.MockResource;
+import org.apache.sling.resource.collection.test.MockResourceResolver;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ResourceCollectionImplTest {
+ private ResourceResolver resResolver;
+
+ @Before
+ public void setUp() throws Exception {
+ resResolver = new MockResourceResolver();
+ //create some root resource
+ Resource resource = new MockResource(resResolver, "/", "type");
+
+ ((MockResourceResolver) resResolver).addResource(resource);
+ }
+
+ @Test
+ public void testAddResource() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "test1");
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource);
+ resource = new MockResource(resResolver, "/res2", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource);
+
+ Assert.assertEquals(true, collection.contains(resource));
+
+ Assert.assertEquals(true, collection.contains(resource));
+ Assert.assertNotNull(resResolver.getResource("/test1"));
+ Assert.assertEquals(ResourceCollection.RESOURCE_TYPE, resResolver.getResource("/test1").getResourceType());
+ }
+
+ @Test
+ public void testCreateCollection() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "test1");
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+ resource = new MockResource(resResolver, "/res2", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+
+ Assert.assertEquals(true, collection.contains(resource));
+ Assert.assertNotNull(resResolver.getResource("/test1"));
+ Assert.assertEquals(ResourceCollection.RESOURCE_TYPE, resResolver.getResource("/test1").getResourceType());
+ }
+
+ @Test
+ public void testGetCollection() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "test1");
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+ resource = new MockResource(resResolver, "/res2", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+
+ collection = rcm.getCollection(resResolver.getResource(collection.getPath()));
+
+ Assert.assertEquals(true, collection.contains(resource));
+ Assert.assertNotNull(resResolver.getResource("/test1"));
+ Assert.assertEquals(ResourceCollection.RESOURCE_TYPE, resResolver.getResource("/test1").getResourceType());
+ }
+
+ @Test
+ public void testListCollection() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "collection1");
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+ resource = new MockResource(resResolver, "/res2", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+
+ Assert.assertEquals(true, collection.contains(resource));
+
+ Iterator<Resource> resources = collection.getResources();
+
+ int numOfRes = 0;
+ while (resources.hasNext()) {
+ resources.next();
+ numOfRes ++;
+ }
+
+ Assert.assertEquals(2, numOfRes);
+ }
+
+ @Test
+ public void testCreateCollectionWithProperties() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, "some/type");
+ props.put("creator", "slingdev");
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "collection3", props);
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+
+
+ Resource collectionRes = resResolver.getResource("/collection3");
+ Assert.assertNotNull(collectionRes);
+
+ Assert.assertEquals(true, collection.contains(resource));
+ Assert.assertEquals(ResourceCollection.RESOURCE_TYPE, collectionRes.getResourceSuperType());
+
+ ValueMap vm = collectionRes.adaptTo(ValueMap.class);
+
+ Assert.assertEquals("slingdev", vm.get("creator", ""));
+ }
+
+ @Test
+ public void testAddResourceWithProperties() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("creator", "slingdev");
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "collection3");
+
+ Resource resource = new MockResource(resResolver, "/res1", "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, props);
+
+
+ Resource collectionRes = resResolver.getResource("/collection3");
+ Assert.assertNotNull(collectionRes);
+
+ Assert.assertEquals(true, collection.contains(resource));
+
+ ValueMap vm = collection.getProperties(resource);
+
+ if (vm != null) {
+ Assert.assertEquals("slingdev", vm.get("creator", ""));
+ } else {
+ Assert.fail("no resource entry in collection");
+ }
+ }
+
+ @Test
+ public void testOrdering() throws Exception {
+ ResourceCollectionManager rcm = new ResourceCollectionManagerImpl(resResolver);
+
+ ResourceCollection collection = rcm.createCollection(resResolver.getResource("/"), "test1");
+ String[] resPaths = {"/res1", "/res2"};
+ Resource resource = new MockResource(resResolver, resPaths[0], "type");
+ ((MockResourceResolver) resResolver).addResource(resource);
+
+ collection.add(resource, null);
+ Resource resource2 = new MockResource(resResolver, resPaths[1], "type");
+ ((MockResourceResolver) resResolver).addResource(resource2);
+
+ collection.add(resource2, null);
+
+ Assert.assertEquals(true, collection.contains(resource2));
+ Assert.assertNotNull(resResolver.getResource("/test1"));
+ Assert.assertEquals(ResourceCollection.RESOURCE_TYPE, resResolver.getResource("/test1").getResourceType());
+
+ Iterator<Resource> resources = collection.getResources();
+
+ int numOfRes = 0;
+ while (resources.hasNext()) {
+ Resource entry = resources.next();
+ Assert.assertEquals(resPaths[numOfRes], entry.getPath());
+ numOfRes ++;
+ }
+
+ //change the order
+ collection.orderBefore(resource2, resource);
+
+ resources = collection.getResources();
+
+ numOfRes = 2;
+ while (resources.hasNext()) {
+ numOfRes --;
+ Resource entry = resources.next();
+ Assert.assertEquals(resPaths[numOfRes], entry.getPath());
+ }
+
+ Assert.assertEquals(0, numOfRes);
+ }
+}
diff --git a/src/test/java/org/apache/sling/resource/collection/test/MockResource.java b/src/test/java/org/apache/sling/resource/collection/test/MockResource.java
new file mode 100755
index 0000000..a97369a
--- /dev/null
+++ b/src/test/java/org/apache/sling/resource/collection/test/MockResource.java
@@ -0,0 +1,104 @@
+/*
+ * 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.resource.collection.test;
+
+import org.apache.sling.api.resource.ModifiableValueMap;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ModifiableValueMapDecorator;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MockResource extends SyntheticResource {
+
+ private String resourceType;
+ private String resourceSuperType;
+ private Map<String,Object> properties = new HashMap<String,Object>();
+
+ public MockResource(ResourceResolver resourceResolver, String path,
+ String resourceType) {
+ this(resourceResolver, path, resourceType, null);
+ }
+
+ public MockResource(ResourceResolver resourceResolver, String path,
+ String resourceType, String resourceSuperType) {
+ super(resourceResolver, path, resourceType);
+
+ setResourceType(resourceType);
+ setResourceSuperType(resourceSuperType);
+ }
+
+ public void addProperty(String key, Object value){
+ this.properties.put(key,value);
+ }
+
+ public Map<String,Object> getProperties(){
+ return this.properties;
+ }
+
+ @Override
+ public String getResourceType() {
+ return resourceType;
+ }
+
+ public void setResourceType(String resourceType) {
+ this.resourceType = resourceType;
+ }
+
+ @Override
+ public String getResourceSuperType() {
+ return resourceSuperType;
+ }
+
+ public void setResourceSuperType(String resourceSuperType) {
+ this.resourceSuperType = resourceSuperType;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ if (type == ValueMap.class) {
+ ValueMap map = new ValueMapDecorator(new HashMap<String, Object>());
+ if (resourceType != null) {
+ map.put("resourceType", resourceType);
+ }
+ if (resourceSuperType != null) {
+ map.put("resourceSuperType", resourceSuperType);
+ }
+ for (String key : this.properties.keySet()) {
+ map.put(key,this.properties.get(key));
+ }
+ return (AdapterType) map;
+ }
+
+ if (type == ModifiableValueMap.class) {
+ ModifiableValueMap map = new ModifiableValueMapDecorator(this.properties);
+ if (resourceType != null) {
+ map.put("resourceType", resourceType);
+ }
+ if (resourceSuperType != null) {
+ map.put("resourceSuperType", resourceSuperType);
+ }
+ return (AdapterType) map;
+ }
+ throw new UnsupportedOperationException("AdaptTo " + type.getSimpleName() + " not implemented");
+ }
+}
diff --git a/src/test/java/org/apache/sling/resource/collection/test/MockResourceResolver.java b/src/test/java/org/apache/sling/resource/collection/test/MockResourceResolver.java
new file mode 100755
index 0000000..5b7d9b3
--- /dev/null
+++ b/src/test/java/org/apache/sling/resource/collection/test/MockResourceResolver.java
@@ -0,0 +1,249 @@
+/*
+ * 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.resource.collection.test;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.JcrResourceConstants;
+
+public class MockResourceResolver implements ResourceResolver {
+
+ private String[] searchPath;
+
+ private Map<String, Resource> resources = new LinkedHashMap<String, Resource>();
+
+ private Map<String, Collection<Resource>> children = new LinkedHashMap<String, Collection<Resource>>();
+
+ public void addResource(Resource resource) {
+ this.resources.put(resource.getPath(), resource);
+ }
+
+ public void addChildren(Resource parent, Collection<Resource> children) {
+ this.children.put(parent.getPath(), children);
+ }
+
+ public Resource resolve(HttpServletRequest request) {
+ throw new UnsupportedOperationException("Not implemented");
+
+ }
+
+ public Resource resolve(String absPath) {
+ throw new UnsupportedOperationException("Not implemented");
+
+ }
+
+ public String map(String resourcePath) {
+ return resourcePath; // a rather simplistic 1:1 map...
+
+ }
+
+ public Resource getResource(String path) {
+ return resources.get(path);
+ }
+
+ public Resource getResource(Resource base, String path) {
+ if (!path.startsWith("/")) {
+ path = base.getPath() + "/" + path;
+ }
+ return getResource(path);
+ }
+
+ public String[] getSearchPath() {
+ return searchPath.clone();
+
+ }
+
+ public Iterator<Resource> listChildren(final Resource parent) {
+ Collection<Resource> childCollection = children.get(parent.getPath());
+ if (childCollection != null) {
+ return childCollection.iterator();
+ }
+
+ return new Iterator<Resource>() {
+ final String parentPath = parent.getPath() + "/";
+
+ final Iterator<Resource> elements = resources.values().iterator();
+
+ Resource nextResource = seek();
+
+ public boolean hasNext() {
+ return nextResource != null;
+ }
+
+ public Resource next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Resource result = nextResource;
+ nextResource = seek();
+ return result;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ private Resource seek() {
+ while (elements.hasNext()) {
+ Resource next = elements.next();
+ String path = next.getPath();
+ if (path.startsWith(parentPath)
+ && path.indexOf('/', parentPath.length()) < 0) {
+ return next;
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ public Iterator<Resource> findResources(String query, String language) {
+ throw new UnsupportedOperationException("Not implemented");
+
+ }
+
+ public Iterator<Map<String, Object>> queryResources(String query,
+ String language) {
+ throw new UnsupportedOperationException("Not implemented");
+
+ }
+
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ throw new UnsupportedOperationException("Not implemented");
+
+ }
+
+ public void setSearchPath(String... searchPath) {
+ if (searchPath == null) {
+ this.searchPath = new String[0];
+ } else {
+ this.searchPath = new String[searchPath.length];
+ for (int i=0; i < searchPath.length; i++) {
+ String entry = searchPath[i];
+ if (!entry.endsWith("/")) {
+ entry = entry.concat("/");
+ }
+ this.searchPath[i] = entry;
+ }
+ }
+ }
+
+ public String map(HttpServletRequest request, String resourcePath) {
+ return request.getContextPath() + resourcePath;
+ }
+
+ public Resource resolve(HttpServletRequest request, String absPath) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ public void close() {
+ // nothing to do
+ }
+
+ public String getUserID() {
+ return null;
+ }
+
+ public boolean isLive() {
+ return true;
+ }
+
+ public ResourceResolver clone(Map<String, Object> authenticationInfo)
+ throws LoginException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Object getAttribute(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Iterator<String> getAttributeNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void commit() throws PersistenceException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Resource create(Resource arg0, String arg1, Map<String, Object> arg2)
+ throws PersistenceException {
+ String superType = "SuperType";
+ String resType = "ResType";
+
+ if (arg2 != null) {
+ if (arg2.containsKey(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY)) {
+ superType = (String) arg2.remove(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY);
+ }
+
+ if (arg2.containsKey(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY)) {
+ resType = (String) arg2.remove(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY);
+ }
+ }
+
+ String resourcePath = arg0.getPath();
+ if (arg0.getPath().equals("/")) {
+ resourcePath = resourcePath + arg1;
+ } else {
+ resourcePath = resourcePath + "/" + arg1;
+ }
+ MockResource resource = new MockResource(this, resourcePath, resType, superType);
+ if (arg2 != null) {
+ for (String key: arg2.keySet()) {
+ resource.addProperty(key, arg2.get(key));
+ }
+ }
+ this.resources.put(resource.getPath(), resource);
+ return resource;
+ }
+
+ public void delete(Resource arg0) throws PersistenceException {
+ // TODO Auto-generated method stub
+ }
+
+ public Iterable<Resource> getChildren(Resource arg0) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean hasChanges() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void revert() {
+ // TODO Auto-generated method stub
+
+ }
+}
+
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.