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