You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2014/11/19 09:04:45 UTC

svn commit: r1640497 - in /sling/trunk/bundles/jcr/resource/src: main/java/org/apache/sling/jcr/resource/internal/ main/java/org/apache/sling/jcr/resource/internal/helper/jcr/ test/java/org/apache/sling/jcr/resource/internal/ test/java/org/apache/sling...

Author: cziegeler
Date: Wed Nov 19 08:04:44 2014
New Revision: 1640497

URL: http://svn.apache.org/r1640497
Log:
SLING-4184 : Provide path mapping from JCR nodes to resource paths

Added:
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java   (with props)
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java   (with props)
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java   (with props)
Modified:
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/OakResourceListener.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerScalabilityTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousOakResourceListener.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/JcrNodeResourceIteratorTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceListener.java Wed Nov 19 08:04:44 2014
@@ -37,6 +37,8 @@ import org.apache.jackrabbit.api.observa
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider;
+import org.apache.sling.jcr.resource.internal.helper.jcr.PathMapper;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventProperties;
@@ -70,6 +72,8 @@ public class JcrResourceListener impleme
     /** Helper object. */
     final ObservationListenerSupport support;
 
+    private final PathMapper pathMapper;
+
     /**
      * Marker event for {@link #processOsgiEventQueue()} to be signaled to
      * terminate processing Events.
@@ -78,8 +82,10 @@ public class JcrResourceListener impleme
 
     public JcrResourceListener(
                     final String mountPrefix,
-                    final ObservationListenerSupport support)
+                    final ObservationListenerSupport support,
+                    final PathMapper pathMapper)
     throws RepositoryException {
+        this.pathMapper = pathMapper;
         boolean foundClass = false;
         try {
             this.getClass().getClassLoader().loadClass(JackrabbitEvent.class.getName());
@@ -289,16 +295,21 @@ public class JcrResourceListener impleme
             final String topic,
             final ChangedAttributes changedAttributes) {
 
-        if (changedAttributes != null) {
-            changedAttributes.mergeAttributesInto(properties);
-        }
+        final String resourcePath = pathMapper.mapJCRPathToResourcePath(path);
+        if ( resourcePath != null ) {
+            if (changedAttributes != null) {
+                changedAttributes.mergeAttributesInto(properties);
+            }
 
-        // set the path (might have been changed for nt:file content)
-        properties.put(SlingConstants.PROPERTY_PATH, path);
-        properties.put(EventConstants.EVENT_TOPIC, topic);
+            // set the path (might have been changed for nt:file content)
+            properties.put(SlingConstants.PROPERTY_PATH, resourcePath);
+            properties.put(EventConstants.EVENT_TOPIC, topic);
 
-        // enqueue event for dispatching
-        this.osgiEventQueue.offer(properties);
+            // enqueue event for dispatching
+            this.osgiEventQueue.offer(properties);
+        } else {
+            logger.error("Dropping observation event for {}", path);
+        }
     }
 
     /**

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/OakResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/OakResourceListener.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/OakResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/OakResourceListener.java Wed Nov 19 08:04:44 2014
@@ -47,6 +47,8 @@ import org.apache.jackrabbit.oak.spi.com
 import org.apache.sling.api.SlingConstants;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider;
+import org.apache.sling.jcr.resource.internal.helper.jcr.PathMapper;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
@@ -71,14 +73,18 @@ public class OakResourceListener extends
     /** Helper object. */
     final ObservationListenerSupport support;
 
+    private final PathMapper pathMapper;
+
     public OakResourceListener(
             final String mountPrefix,
             final ObservationListenerSupport support,
             final BundleContext bundleContext,
-            final Executor executor)
+            final Executor executor,
+            final PathMapper pathMapper)
     throws RepositoryException {
         super("/", "jcr:primaryType", "sling:resourceType", "sling:resourceSuperType");
         this.support = support;
+        this.pathMapper = pathMapper;
         this.mountPrefix = (mountPrefix == null || mountPrefix.length() == 0 || mountPrefix.equals("/") ? null : mountPrefix);
 
         final Dictionary<String, Object> props = new Hashtable<String, Object>();
@@ -243,7 +249,14 @@ public class OakResourceListener extends
                 }
 
                 if ( sendEvent ) {
-                    localEa.sendEvent(new org.osgi.service.event.Event(topic, new EventProperties(changes)));
+                    final String resourcePath = pathMapper.mapJCRPathToResourcePath(changes.get(SlingConstants.PROPERTY_PATH).toString());
+                    if ( resourcePath != null ) {
+                        changes.put(SlingConstants.PROPERTY_PATH, resourcePath);
+
+                        localEa.sendEvent(new org.osgi.service.event.Event(topic, new EventProperties(changes)));
+                    } else {
+                        logger.debug("Dropping observation event for {}", changes.get(SlingConstants.PROPERTY_PATH));
+                    }
                 }
             }
         } catch (final Exception e) {

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java Wed Nov 19 08:04:44 2014
@@ -53,15 +53,19 @@ abstract class JcrItemResource<T extends
 
     private final ResourceMetadata metadata;
 
+    private final PathMapper pathMapper;
+
     protected JcrItemResource(final ResourceResolver resourceResolver,
                               final String path,
                               final T item,
-                              final ResourceMetadata metadata) {
+                              final ResourceMetadata metadata,
+                              final PathMapper pathMapper) {
 
         this.resourceResolver = resourceResolver;
         this.path = path;
         this.item = item;
         this.metadata = metadata;
+        this.pathMapper = pathMapper;
     }
 
     /**

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java Wed Nov 19 08:04:44 2014
@@ -69,6 +69,8 @@ class JcrNodeResource extends JcrItemRes
 
     private final ClassLoader dynamicClassLoader;
 
+    private final PathMapper pathMapper;
+
     /**
      * Constructor
      * @param resourceResolver
@@ -80,8 +82,10 @@ class JcrNodeResource extends JcrItemRes
     public JcrNodeResource(final ResourceResolver resourceResolver,
                            final String path,
                            final Node node,
-                           final ClassLoader dynamicClassLoader) {
-        super(resourceResolver, path, node, new JcrNodeResourceMetadata(node));
+                           final ClassLoader dynamicClassLoader,
+                           final PathMapper pathMapper) {
+        super(resourceResolver, path, node, new JcrNodeResourceMetadata(node), pathMapper);
+        this.pathMapper = pathMapper;
         this.dynamicClassLoader = dynamicClassLoader;
         this.resourceSuperType = UNSET_RESOURCE_SUPER_TYPE;
     }
@@ -259,7 +263,7 @@ class JcrNodeResource extends JcrItemRes
         try {
             if (getNode().hasNodes()) {
                 return new JcrNodeResourceIterator(getResourceResolver(),
-                    getNode().getNodes(), this.dynamicClassLoader);
+                    getNode().getNodes(), this.dynamicClassLoader, pathMapper);
             }
         } catch (final RepositoryException re) {
             LOGGER.error("listChildren: Cannot get children of " + this, re);

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java Wed Nov 19 08:04:44 2014
@@ -51,16 +51,20 @@ public class JcrNodeResourceIterator imp
 
     private final ClassLoader dynamicClassLoader;
 
+    private final PathMapper pathMapper;
+
     /**
      * Creates an instance using the given resource manager and the nodes
      * provided as a node iterator.
      */
     public JcrNodeResourceIterator(final ResourceResolver resourceResolver,
                                    final NodeIterator nodes,
-                                   final ClassLoader dynamicClassLoader) {
+                                   final ClassLoader dynamicClassLoader,
+                                   final PathMapper pathMapper) {
         this.resourceResolver = resourceResolver;
         this.nodes = nodes;
         this.dynamicClassLoader = dynamicClassLoader;
+        this.pathMapper = pathMapper;
         this.nextResult = seek();
     }
 
@@ -90,11 +94,14 @@ public class JcrNodeResourceIterator imp
         while (nodes.hasNext()) {
             try {
                 final Node n = nodes.nextNode();
-                Resource resource = new JcrNodeResource(resourceResolver,
-                    n.getPath(),
-                    n, dynamicClassLoader);
-                LOGGER.debug("seek: Returning Resource {}", resource);
-                return resource;
+                final String path = pathMapper.mapJCRPathToResourcePath(n.getPath());
+                if ( path != null ) {
+                    final Resource resource = new JcrNodeResource(resourceResolver,
+                        path,
+                        n, dynamicClassLoader, pathMapper);
+                    LOGGER.debug("seek: Returning Resource {}", resource);
+                    return resource;
+                }
             } catch (final Throwable t) {
                 LOGGER.error(
                     "seek: Problem creating Resource for next node, skipping",

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java Wed Nov 19 08:04:44 2014
@@ -53,9 +53,10 @@ class JcrPropertyResource extends JcrIte
 
     public JcrPropertyResource(final ResourceResolver resourceResolver,
                                final String path,
-                               final Property property)
+                               final Property property,
+                               final PathMapper pathMapper)
     throws RepositoryException {
-        super(resourceResolver, path, property, new ResourceMetadata());
+        super(resourceResolver, path, property, new ResourceMetadata(), pathMapper);
         this.resourceType = getResourceTypeForNode(property.getParent())
                 + "/" + property.getName();
         if (PropertyType.BINARY != getProperty().getType()) {

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java Wed Nov 19 08:04:44 2014
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 import javax.jcr.Item;
@@ -104,13 +105,16 @@ public class JcrResourceProvider
     private final Session session;
     private final ClassLoader dynamicClassLoader;
     private final RepositoryHolder repositoryHolder;
+    private final PathMapper pathMapper;
 
     public JcrResourceProvider(final Session session,
                                final ClassLoader dynamicClassLoader,
-                               final RepositoryHolder repositoryHolder) {
+                               final RepositoryHolder repositoryHolder,
+                               final PathMapper pathMapper) {
         this.session = session;
         this.dynamicClassLoader = dynamicClassLoader;
         this.repositoryHolder = repositoryHolder;
+        this.pathMapper = pathMapper;
     }
 
     // ---------- ResourceProvider interface ----------------------------------
@@ -179,30 +183,31 @@ public class JcrResourceProvider
      * read-access for the session of this resolver, <code>null</code> is
      * returned.
      *
-     * @param path The absolute path
+     * @param resourcePath The absolute path
      * @return The <code>Resource</code> for the item at the given path.
      * @throws RepositoryException If an error occurrs accessingor checking the
      *             item in the repository.
      */
     private JcrItemResource createResource(final ResourceResolver resourceResolver,
-            final String path) throws RepositoryException {
-        if (itemExists(path)) {
-            Item item = session.getItem(path);
+            final String resourcePath) throws RepositoryException {
+        final String jcrPath = pathMapper.mapResourcePathToJCRPath(resourcePath);
+        if (jcrPath != null && itemExists(jcrPath)) {
+            Item item = session.getItem(jcrPath);
             if (item.isNode()) {
                 log.debug(
                     "createResource: Found JCR Node Resource at path '{}'",
-                    path);
-                return new JcrNodeResource(resourceResolver, path, (Node) item, dynamicClassLoader);
+                    resourcePath);
+                return new JcrNodeResource(resourceResolver, resourcePath, (Node) item, dynamicClassLoader, pathMapper);
             }
 
             log.debug(
                 "createResource: Found JCR Property Resource at path '{}'",
-                path);
-            return new JcrPropertyResource(resourceResolver, path,
-                (Property) item);
+                resourcePath);
+            return new JcrPropertyResource(resourceResolver, resourcePath,
+                (Property) item, pathMapper);
         }
 
-        log.debug("createResource: No JCR Item exists at path '{}'", path);
+        log.debug("createResource: No JCR Item exists at path '{}'", jcrPath);
         return null;
     }
 
@@ -262,7 +267,7 @@ public class JcrResourceProvider
 
         try {
             final QueryResult res = JcrResourceUtil.query(session, query, language);
-            return new JcrNodeResourceIterator(resolver, res.getNodes(), this.dynamicClassLoader);
+            return new JcrNodeResourceIterator(resolver, res.getNodes(), this.dynamicClassLoader, pathMapper);
         } catch (final javax.jcr.query.InvalidQueryException iqe) {
             throw new QuerySyntaxException(iqe.getMessage(), query, language, iqe);
         } catch (final RepositoryException re) {
@@ -279,49 +284,71 @@ public class JcrResourceProvider
         final String queryLanguage = isSupportedQueryLanguage(language) ? language : DEFAULT_QUERY_LANGUAGE;
 
         try {
-            QueryResult result = JcrResourceUtil.query(session, query,
-                queryLanguage);
+            final QueryResult result = JcrResourceUtil.query(session, query, queryLanguage);
             final String[] colNames = result.getColumnNames();
             final RowIterator rows = result.getRows();
+
             return new Iterator<ValueMap>() {
+
+                private ValueMap next;
+
+                {
+                    seek();
+                }
                 public boolean hasNext() {
-                    return rows.hasNext();
+                    return next != null;
                 };
 
                 public ValueMap next() {
-                    final Map<String, Object> row = new HashMap<String, Object>();
-                    try {
-                        Row jcrRow = rows.nextRow();
-                        boolean didPath = false;
-                        boolean didScore = false;
-                        Value[] values = jcrRow.getValues();
-                        for (int i = 0; i < values.length; i++) {
-                            Value v = values[i];
-                            if (v != null) {
-                                String colName = colNames[i];
-                                row.put(colName,
-                                    JcrResourceUtil.toJavaObject(values[i]));
-                                if (colName.equals(QUERY_COLUMN_PATH)) {
-                                    didPath = true;
+                    if ( next == null ) {
+                        throw new NoSuchElementException();
+                    }
+                    final ValueMap result = next;
+                    seek();
+                    return result;
+                }
+
+                private void seek() {
+                    while ( next == null && rows.hasNext() ) {
+                        try {
+                            final Row jcrRow = rows.nextRow();
+                            final String resourcePath = pathMapper.mapJCRPathToResourcePath(jcrRow.getPath());
+                            if ( resourcePath != null ) {
+                                final Map<String, Object> row = new HashMap<String, Object>();
+
+                                boolean didPath = false;
+                                boolean didScore = false;
+                                final Value[] values = jcrRow.getValues();
+                                for (int i = 0; i < values.length; i++) {
+                                    Value v = values[i];
+                                    if (v != null) {
+                                        String colName = colNames[i];
+                                        row.put(colName,
+                                            JcrResourceUtil.toJavaObject(values[i]));
+                                        if (colName.equals(QUERY_COLUMN_PATH)) {
+                                            didPath = true;
+                                            row.put(colName,
+                                                    pathMapper.mapJCRPathToResourcePath(JcrResourceUtil.toJavaObject(values[i]).toString()));
+                                        }
+                                        if (colName.equals(QUERY_COLUMN_SCORE)) {
+                                            didScore = true;
+                                        }
+                                    }
+                                }
+                                if (!didPath) {
+                                    row.put(QUERY_COLUMN_PATH, pathMapper.mapJCRPathToResourcePath(jcrRow.getPath()));
                                 }
-                                if (colName.equals(QUERY_COLUMN_SCORE)) {
-                                    didScore = true;
+                                if (!didScore) {
+                                    row.put(QUERY_COLUMN_SCORE, jcrRow.getScore());
                                 }
+                                next = new ValueMapDecorator(row);
                             }
+                        } catch (final RepositoryException re) {
+                            log.error(
+                                "queryResources$next: Problem accessing row values",
+                                re);
                         }
-                        if (!didPath) {
-                            row.put(QUERY_COLUMN_PATH, jcrRow.getPath());
-                        }
-                        if (!didScore) {
-                            row.put(QUERY_COLUMN_SCORE, jcrRow.getScore());
-                        }
-
-                    } catch (RepositoryException re) {
-                        log.error(
-                            "queryResources$next: Problem accessing row values",
-                            re);
                     }
-                    return new ValueMapDecorator(row);
                 }
 
                 public void remove() {
@@ -413,7 +440,7 @@ public class JcrResourceProvider
     /**
      * @see org.apache.sling.api.resource.ModifyingResourceProvider#create(ResourceResolver, java.lang.String, Map)
      */
-    public Resource create(final ResourceResolver resolver, final String path, final Map<String, Object> properties)
+    public Resource create(final ResourceResolver resolver, final String resourcePath, final Map<String, Object> properties)
     throws PersistenceException {
         // check for node type
         final Object nodeObj = (properties != null ? properties.get(NodeUtil.NODE_TYPE) : null);
@@ -441,16 +468,20 @@ public class JcrResourceProvider
                 nodeType = null;
             }
         }
+        final String jcrPath = pathMapper.mapResourcePathToJCRPath(resourcePath);
+        if ( jcrPath == null ) {
+            throw new PersistenceException("Unable to create node at " + resourcePath, null, resourcePath, null);
+        }
         Node node = null;
         try {
-            final int lastPos = path.lastIndexOf('/');
+            final int lastPos = jcrPath.lastIndexOf('/');
             final Node parent;
             if ( lastPos == 0 ) {
                 parent = this.session.getRootNode();
             } else {
-                parent = (Node)this.session.getItem(path.substring(0, lastPos));
+                parent = (Node)this.session.getItem(jcrPath.substring(0, lastPos));
             }
-            final String name = path.substring(lastPos + 1);
+            final String name = jcrPath.substring(lastPos + 1);
             if ( nodeType != null ) {
                 node = parent.addNode(name, nodeType);
             } else {
@@ -475,31 +506,35 @@ public class JcrResourceProvider
                             } catch ( final RepositoryException re) {
                                 // we ignore this
                             }
-                            throw new PersistenceException(iae.getMessage(), iae, path, entry.getKey());
+                            throw new PersistenceException(iae.getMessage(), iae, resourcePath, entry.getKey());
                         }
                     }
                 }
             }
 
-            return new JcrNodeResource(resolver, path, node, this.dynamicClassLoader);
+            return new JcrNodeResource(resolver, resourcePath, node, this.dynamicClassLoader, pathMapper);
         } catch (final RepositoryException e) {
-            throw new PersistenceException("Unable to create node at " + path, e, path, null);
+            throw new PersistenceException("Unable to create node at " + jcrPath, e, resourcePath, null);
         }
     }
 
     /**
      * @see org.apache.sling.api.resource.ModifyingResourceProvider#delete(ResourceResolver, java.lang.String)
      */
-    public void delete(final ResourceResolver resolver, final String path)
+    public void delete(final ResourceResolver resolver, final String resourcePath)
     throws PersistenceException {
+        final String jcrPath = pathMapper.mapResourcePathToJCRPath(resourcePath);
+        if ( jcrPath == null ) {
+            throw new PersistenceException("Unable to delete resource at " + resourcePath, null, resourcePath, null);
+        }
         try {
-            if ( session.itemExists(path) ) {
-                session.getItem(path).remove();
+            if ( session.itemExists(jcrPath) ) {
+                session.getItem(jcrPath).remove();
             } else {
-                throw new PersistenceException("Unable to delete resource at " + path + ". Resource does not exist.", null, path, null);
+                throw new PersistenceException("Unable to delete resource at " + jcrPath + ". Resource does not exist.", null, resourcePath, null);
             }
         } catch (final RepositoryException e) {
-            throw new PersistenceException("Unable to delete resource at " + path, e, path, null);
+            throw new PersistenceException("Unable to delete resource at " + jcrPath, e, resourcePath, null);
         }
     }
 

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderFactory.java Wed Nov 19 08:04:44 2014
@@ -108,6 +108,9 @@ public class JcrResourceProviderFactory 
     @Reference(policy=ReferencePolicy.STATIC, cardinality=ReferenceCardinality.OPTIONAL_UNARY)
     private Executor executor;
 
+    @Reference
+    private PathMapper pathMapper;
+
     /** The JCR observation listener. */
     private Closeable listener;
 
@@ -144,7 +147,7 @@ public class JcrResourceProviderFactory 
         try {
             if ( isOak ) {
                 try {
-                    this.listener = new OakResourceListener(root, support, context.getBundleContext(), executor);
+                    this.listener = new OakResourceListener(root, support, context.getBundleContext(), executor, pathMapper);
                     log.info("Detected Oak based repository. Using improved JCR Resource Listener");
                 } catch ( final RepositoryException re ) {
                     throw re;
@@ -153,7 +156,7 @@ public class JcrResourceProviderFactory 
                 }
             }
             if ( this.listener == null ) {
-                this.listener = new JcrResourceListener(root, support);
+                this.listener = new JcrResourceListener(root, support, pathMapper);
             }
             closeSupport = false;
         } finally {
@@ -344,7 +347,7 @@ public class JcrResourceProviderFactory 
             holder.setSession(session);
         }
 
-        return new JcrResourceProvider(session, this.getDynamicClassLoader(), holder);
+        return new JcrResourceProvider(session, this.getDynamicClassLoader(), holder, pathMapper);
     }
 
     /**

Added: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java?rev=1640497&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java (added)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java Wed Nov 19 08:04:44 2014
@@ -0,0 +1,166 @@
+/*
+ * 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.jcr.resource.internal.helper.jcr;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@code PathMapper} allows to
+ * - map path from the JCR resource tree to resource paths
+ * - hide JCR nodes; however this is not a security feature
+ */
+@Service(value = PathMapper.class)
+@Component(metatype = true,
+        label = "Apache Sling JCR Resource Provider Path Mapper",
+        description = "This service provides path mappings for JCR nodes.")
+public class PathMapper {
+
+    /** Logger */
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Property(unbounded = PropertyUnbounded.ARRAY,
+            label = "Path mapping", description = "Defines an obtional path mapping for a path." +
+            "Each mapping entry is expressed as follow: <JCRPath>:<resourcePath>. As an example: /foo:/libs, " +
+            "this maps the JCR node /foo to the resource /libs. If the resource path is specified as '.', " +
+            " the JCR tree is not visible in the resource tree. This should not be considered a security feature " +
+            " as the nodes are still accessible through the JCR api. Mapping a JCR path to the root is not allowed. " +
+            "The mappings are evaluated as ordered in the configuration.")
+    private static final String PATH_MAPPING = "path.mapping";
+
+    /** The mappings. */
+    private final List<Mapping> mappings = new ArrayList<Mapping>();
+
+    private static final class Mapping {
+        public final String jcrPath;
+        public final String resourcePath;
+        public final String jcrPathPrefix;
+        public final String resourcePathPrefix;
+
+        public Mapping(final String path, final String mappedPath) {
+            this.jcrPath = path;
+            this.jcrPathPrefix = path.concat("/");
+            if ( mappedPath.equals(".") ) {
+                this.resourcePath = null;
+                this.resourcePathPrefix = null;
+            } else {
+                this.resourcePath = mappedPath;
+                this.resourcePathPrefix = mappedPath.concat("/");
+            }
+        }
+    }
+
+    @Activate
+    private void activate(final Map<String, Object> props) {
+        mappings.clear();
+        final String[] config = PropertiesUtil.toStringArray(props.get(PATH_MAPPING), null);
+        if ( config != null ) {
+            for (final String mapping : config) {
+                boolean valid = false;
+                final String[] parts = mapping.split(":");
+                if (parts.length == 2) {
+                    parts[0] = parts[0].trim();
+                    parts[1] = parts[1].trim();
+                    if ( parts[0].startsWith("/") && (parts[1].startsWith("/") || parts[1].equals(".")) ) {
+                        if ( parts[0].endsWith("/") ) {
+                            parts[0] = parts[0].substring(0, parts[1].length() - 1);
+                        }
+                        if ( parts[1].endsWith("/") ) {
+                            parts[1] = parts[1].substring(0, parts[1].length() - 1);
+                        }
+                        if ( parts[0].length() > 1 && (parts[1].length() > 1 || parts[1].equals(".")) ) {
+                            mappings.add(new Mapping(parts[0], parts[1]));
+                            valid = true;
+                        }
+                    }
+                }
+                if ( !valid ) {
+                    log.warn("Invalid mapping configuration (skipping): {}", mapping);
+                }
+            }
+        }
+    }
+
+    /**
+     * Map a resource path to a JCR path
+     * @param resourcePath The resource path
+     * @return The JCR path or {@code null}
+     */
+    public String mapResourcePathToJCRPath(final String resourcePath) {
+        String jcrPath = resourcePath;
+        if (resourcePath != null && !mappings.isEmpty()) {
+            for (final Mapping mapping : mappings) {
+                if ( mapping.resourcePath == null ) {
+                    if ( resourcePath.equals(mapping.jcrPath) || resourcePath.startsWith(mapping.jcrPathPrefix) ) {
+                        jcrPath = null;
+                        break;
+                    }
+                } else {
+                    if (resourcePath.equals(mapping.resourcePath)) {
+                        jcrPath = mapping.jcrPath;
+                        break;
+                    } else if (resourcePath.startsWith(mapping.resourcePathPrefix)) {
+                        jcrPath = mapping.jcrPathPrefix.concat(resourcePath.substring(mapping.resourcePathPrefix.length()));
+                        break;
+                    }
+                }
+            }
+        }
+        return jcrPath;
+    }
+
+    /**
+     * Map a JCR path to a resource path
+     * @param jcrPath The JCR path
+     * @return The resource path or {@code null}
+     */
+    public String mapJCRPathToResourcePath(final String jcrPath) {
+        String resourcePath = jcrPath;
+        if (jcrPath != null && !mappings.isEmpty()) {
+            for (final Mapping mapping : mappings) {
+                if (mapping.resourcePath != null && (jcrPath.equals(mapping.resourcePath) || jcrPath.startsWith(mapping.resourcePathPrefix)) ) {
+                    resourcePath = null;
+                    break;
+                } else if (jcrPath.equals(mapping.jcrPath)) {
+                    resourcePath = mapping.resourcePath;
+                    break;
+                } else if (jcrPath.startsWith(mapping.jcrPathPrefix)) {
+                    if ( mapping.resourcePath == null ) {
+                        resourcePath = null;
+                    } else {
+                        resourcePath = mapping.resourcePathPrefix.concat(jcrPath.substring(mapping.jcrPathPrefix.length()));
+                    }
+                    break;
+                }
+            }
+        }
+        return resourcePath;
+    }
+}

Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerScalabilityTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerScalabilityTest.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerScalabilityTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerScalabilityTest.java Wed Nov 19 08:04:44 2014
@@ -65,7 +65,7 @@ public class JcrResourceListenerScalabil
         when(bundleContext.getServiceReferences(anyString(), anyString())).thenReturn(serviceRefs);
         when(bundleContext.getService(serviceRef)).thenReturn(eventAdmin);
 
-        jcrResourceListener = new JcrResourceListener("/", new ObservationListenerSupport(bundleContext, repository));
+        jcrResourceListener = new JcrResourceListener("/", new ObservationListenerSupport(bundleContext, repository), new PathMapperImpl());
 
         Event event = mock(MockEvent.class);
         events = mock(EventIterator.class);

Added: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java?rev=1640497&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java (added)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java Wed Nov 19 08:04:44 2014
@@ -0,0 +1,33 @@
+/*
+ * 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.jcr.resource.internal;
+
+import org.apache.sling.jcr.resource.internal.helper.jcr.PathMapper;
+
+
+public class PathMapperImpl extends PathMapper {
+
+    @Override
+    public String mapResourcePathToJCRPath(String path) {
+        return path;
+    }
+
+    @Override
+    public String mapJCRPathToResourcePath(String path) {
+        return path;
+    }
+}

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/PathMapperImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java Wed Nov 19 08:04:44 2014
@@ -44,7 +44,7 @@ public class SynchronousJcrResourceListe
             final ResourceResolver resolver,
             final ServiceTracker tracker)
             throws LoginException, RepositoryException, NoSuchFieldException {
-        super("/", new ObservationListenerSupport(bundleContext, repo));
+        super("/", new ObservationListenerSupport(bundleContext, repo), new PathMapperImpl());
         PrivateAccessor.setField(this.support, "resourceResolver", resolver);
         PrivateAccessor.setField(this.support, "eventAdminTracker", tracker);
     }

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousOakResourceListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousOakResourceListener.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousOakResourceListener.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousOakResourceListener.java Wed Nov 19 08:04:44 2014
@@ -45,7 +45,7 @@ public class SynchronousOakResourceListe
             final ServiceTracker tracker,
             final Executor executor)
             throws LoginException, RepositoryException, NoSuchFieldException {
-        super("/", new ObservationListenerSupport(bundleContext, repo), bundleContext, executor);
+        super("/", new ObservationListenerSupport(bundleContext, repo), bundleContext, executor, new PathMapperImpl());
         PrivateAccessor.setField(this.support, "resourceResolver", resolver);
         PrivateAccessor.setField(this.support, "eventAdminTracker", tracker);
     }

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/JcrNodeResourceIteratorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/JcrNodeResourceIteratorTest.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/JcrNodeResourceIteratorTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/JcrNodeResourceIteratorTest.java Wed Nov 19 08:04:44 2014
@@ -29,13 +29,14 @@ import junit.framework.TestCase;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.commons.testing.jcr.MockNode;
 import org.apache.sling.commons.testing.jcr.MockNodeIterator;
+import org.apache.sling.jcr.resource.internal.PathMapperImpl;
 import org.apache.sling.jcr.resource.internal.helper.jcr.JcrNodeResourceIterator;
 
 public class JcrNodeResourceIteratorTest extends TestCase {
 
     public void testEmpty() {
         NodeIterator ni = new MockNodeIterator(null);
-        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null);
+        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null, new PathMapperImpl());
 
         assertFalse(ri.hasNext());
 
@@ -51,7 +52,7 @@ public class JcrNodeResourceIteratorTest
         String path = "/parent/path/node";
         Node node = new MockNode(path);
         NodeIterator ni = new MockNodeIterator(new Node[] { node });
-        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null);
+        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null, new PathMapperImpl());
 
         assertTrue(ri.hasNext());
         Resource res = ri.next();
@@ -76,7 +77,7 @@ public class JcrNodeResourceIteratorTest
             nodes[i] = new MockNode(pathBase + i, "some:type" + i);
         }
         NodeIterator ni = new MockNodeIterator(nodes);
-        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null);
+        JcrNodeResourceIterator ri = new JcrNodeResourceIterator(null, ni, null, new PathMapperImpl());
 
         for (int i=0; i < nodes.length; i++) {
             assertTrue(ri.hasNext());

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java Wed Nov 19 08:04:44 2014
@@ -31,6 +31,7 @@ import org.apache.jackrabbit.JcrConstant
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceMetadata;
 import org.apache.sling.jcr.resource.JcrResourceConstants;
+import org.apache.sling.jcr.resource.internal.PathMapperImpl;
 
 public class JcrNodeResourceTest extends JcrItemResourceTestBase {
 
@@ -44,7 +45,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         file = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
 
         assertEquals(file.getPath(), jnr.getPath());
 
@@ -62,7 +63,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         file = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
 
         assertEquals(file.getPath(), jnr.getPath());
 
@@ -78,7 +79,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         res = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
 
         assertEquals(res.getPath(), jnr.getPath());
 
@@ -94,7 +95,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         res = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
 
         assertEquals(res.getPath(), jnr.getPath());
 
@@ -107,14 +108,14 @@ public class JcrNodeResourceTest extends
         Node node = rootNode.addNode(name, JcrConstants.NT_UNSTRUCTURED);
         getSession().save();
 
-        JcrNodeResource jnr = new JcrNodeResource(null, node.getPath(), node, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
         assertEquals(JcrConstants.NT_UNSTRUCTURED, jnr.getResourceType());
 
         String typeName = "some/resource/type";
         node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, typeName);
         getSession().save();
 
-        jnr = new JcrNodeResource(null, node.getPath(), node, null);
+        jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
         assertEquals(typeName, jnr.getResourceType());
     }
 
@@ -126,7 +127,7 @@ public class JcrNodeResourceTest extends
         node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, typeName);
         getSession().save();
 
-        Resource jnr = new JcrNodeResource(null, node.getPath(), node, null);
+        Resource jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
         assertEquals(typeName, jnr.getResourceType());
 
         // default super type is null
@@ -137,7 +138,7 @@ public class JcrNodeResourceTest extends
         typeNode.setProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY, superTypeName);
         getSession().save();
 
-        jnr = new JcrNodeResource(null, typeNode.getPath(), typeNode, null);
+        jnr = new JcrNodeResource(null, typeNode.getPath(), typeNode, null, new PathMapperImpl());
         assertEquals(JcrConstants.NT_UNSTRUCTURED, jnr.getResourceType());
         assertEquals(superTypeName, jnr.getResourceSuperType());
 
@@ -146,7 +147,7 @@ public class JcrNodeResourceTest extends
         node.setProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY, otherSuperTypeName);
         getSession().save();
 
-        jnr = new JcrNodeResource(null, node.getPath(), node, null);
+        jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
         assertEquals(typeName, jnr.getResourceType());
         assertEquals(otherSuperTypeName, jnr.getResourceSuperType());
 
@@ -154,7 +155,7 @@ public class JcrNodeResourceTest extends
         node.getProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY).remove();
         getSession().save();
 
-        jnr = new JcrNodeResource(null, node.getPath(), node, null);
+        jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
         assertEquals(typeName, jnr.getResourceType());
         assertNull(jnr.getResourceSuperType());
     }
@@ -167,7 +168,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         res = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
 
         final Map<?, ?> props = jnr.adaptTo(Map.class);
 
@@ -234,7 +235,7 @@ public class JcrNodeResourceTest extends
         getSession().save();
 
         file = rootNode.getNode(name);
-        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null);
+        JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
 
         assertEquals(utf8bytes, jnr.adaptTo(InputStream.class));
         assertEquals(utf8bytes.length, jnr.getResourceMetadata().getContentLength());

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java Wed Nov 19 08:04:44 2014
@@ -30,6 +30,7 @@ import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.internal.PathMapperImpl;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.jmock.integration.junit4.JMock;
@@ -72,7 +73,7 @@ public class JcrPropertyResourceTest {
                 allowing(property).getType(); will(returnValue(data.getValue()));
                 allowing(property).getString(); will(returnValue(stringValue));
             }});
-            final JcrPropertyResource propResource = new JcrPropertyResource(resolver, "/path/to/string-property", property);
+            final JcrPropertyResource propResource = new JcrPropertyResource(resolver, "/path/to/string-property", property, new PathMapperImpl());
             assertEquals("Byte length of " +  stringValue, stringByteLength, propResource.getResourceMetadata().getContentLength());
         }
     }

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java?rev=1640497&r1=1640496&r2=1640497&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java Wed Nov 19 08:04:44 2014
@@ -22,12 +22,13 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.jcr.resource.internal.PathMapperImpl;
 
 public class JcrTestNodeResource extends JcrNodeResource {
 
     public JcrTestNodeResource(ResourceResolver resourceResolver, Node node,
             ClassLoader dynamicClassLoader) throws RepositoryException {
-        super(resourceResolver, node.getPath(), node, dynamicClassLoader);
+        super(resourceResolver, node.getPath(), node, dynamicClassLoader, new PathMapperImpl());
     }
 
 }

Added: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java?rev=1640497&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java (added)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java Wed Nov 19 08:04:44 2014
@@ -0,0 +1,70 @@
+/*
+ * 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.jcr.resource.internal.helper.jcr;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junitx.util.PrivateAccessor;
+
+import org.junit.Test;
+
+public class PathMapperTest {
+
+    @Test public void mappingTest() throws Throwable {
+        final Map<String, Object> config = new HashMap<String, Object>();
+        config.put("path.mapping", new String[] {
+                "/libs:/foo",
+                "/hidden:.",
+                "/deep/node:/deep/resource"
+        });
+        final PathMapper pm = new PathMapper();
+        PrivateAccessor.invoke(pm, "activate", new Class[] {Map.class}, new Object[] {config});
+
+        assertEquals("/", pm.mapResourcePathToJCRPath("/"));
+        assertEquals("/", pm.mapJCRPathToResourcePath("/"));
+
+        assertEquals("/unmapped", pm.mapResourcePathToJCRPath("/unmapped"));
+        assertEquals("/unmapped", pm.mapJCRPathToResourcePath("/unmapped"));
+        assertEquals("/unmapped/a", pm.mapResourcePathToJCRPath("/unmapped/a"));
+        assertEquals("/unmapped/a", pm.mapJCRPathToResourcePath("/unmapped/a"));
+
+        assertEquals("/libs", pm.mapResourcePathToJCRPath("/foo"));
+        assertEquals("/foo", pm.mapJCRPathToResourcePath("/libs"));
+        assertEquals("/foo1", pm.mapResourcePathToJCRPath("/foo1"));
+        assertEquals("/libs1", pm.mapJCRPathToResourcePath("/libs1"));
+        assertEquals("/libs/a", pm.mapResourcePathToJCRPath("/foo/a"));
+        assertEquals("/foo/a", pm.mapJCRPathToResourcePath("/libs/a"));
+
+        assertEquals("/deep/node", pm.mapResourcePathToJCRPath("/deep/resource"));
+        assertEquals("/deep/resource", pm.mapJCRPathToResourcePath("/deep/node"));
+        assertEquals("/deep/node/a", pm.mapResourcePathToJCRPath("/deep/resource/a"));
+        assertEquals("/deep/resource/a", pm.mapJCRPathToResourcePath("/deep/node/a"));
+
+        assertNull(pm.mapResourcePathToJCRPath("/hidden"));
+        assertNull(pm.mapResourcePathToJCRPath("/hidden/a"));
+        assertEquals("/hidden1", pm.mapResourcePathToJCRPath("/hidden1"));
+        assertNull(pm.mapJCRPathToResourcePath("/hidden"));
+        assertNull(pm.mapJCRPathToResourcePath("/hidden/a"));
+        assertEquals("/hidden1", pm.mapJCRPathToResourcePath("/hidden1"));
+    }
+}

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Propchange: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/PathMapperTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain