You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2010/04/13 21:13:32 UTC

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

Author: justin
Date: Tue Apr 13 19:13:31 2010
New Revision: 933747

URL: http://svn.apache.org/viewvc?rev=933747&view=rev
Log:
SLING-1447 - committing first pass at workspace names in resource paths

Added:
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
Modified:
    sling/trunk/bundles/jcr/resource/pom.xml
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java
    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/JcrResourceResolver.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java
    sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java
    sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java

Modified: sling/trunk/bundles/jcr/resource/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/pom.xml?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/pom.xml (original)
+++ sling/trunk/bundles/jcr/resource/pom.xml Tue Apr 13 19:13:31 2010
@@ -125,6 +125,7 @@
         <dependency>
             <groupId>javax.jcr</groupId>
             <artifactId>jcr</artifactId>
+            <version>2.0</version>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -203,7 +204,7 @@
         <dependency>
             <groupId>org.apache.jackrabbit</groupId>
             <artifactId>jackrabbit-jcr-commons</artifactId>
-            <version>1.6.0</version>
+            <version>2.0.0</version>
             <scope>provided</scope>
         </dependency>
 
@@ -211,7 +212,25 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.testing</artifactId>
-            <version>2.0.4-incubator</version>
+            <version>2.0.5-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+        	<groupId>org.mockito</groupId>
+        	<artifactId>mockito-all</artifactId>
+        	<version>1.8.2</version>
+        	<scope>test</scope>
+        </dependency>
+        <dependency>
+        	<groupId>junit-addons</groupId>
+        	<artifactId>junit-addons</artifactId>
+        	<version>1.4</version>
+        	<scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-api</artifactId>
+            <version>2.0.0</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java Tue Apr 13 19:13:31 2010
@@ -54,8 +54,9 @@ public class JcrResourceConstants {
     public static final String SLING_RESOURCE_SUPER_TYPE_PROPERTY = "sling:resourceSuperType";
 
     /**
-     * The name of the event property holding the workspace name.
+     * The name of the authentication info property containing the workspace name.
+     *
      * @since 2.0.8
      */
-    public static final String PROPERTY_WORKSPACE = "workspace";
+    public static final String AUTH_INFO_WORKSPACE = "user.jcr.workspace";
 }

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=933747&r1=933746&r2=933747&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 Tue Apr 13 19:13:31 2010
@@ -19,8 +19,10 @@
 package org.apache.sling.jcr.resource.internal;
 
 import java.util.Dictionary;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.Map;
 import java.util.Set;
 
 import javax.jcr.Node;
@@ -31,12 +33,13 @@ import javax.jcr.observation.EventIterat
 import javax.jcr.observation.EventListener;
 
 import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.jcr.api.SlingRepository;
 import org.apache.sling.jcr.resource.JcrResourceConstants;
-import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
@@ -82,14 +85,16 @@ public class JcrResourceListener impleme
      */
     public JcrResourceListener(final SlingRepository repository,
                                final String workspaceName,
-                               final JcrResourceResolverFactory factory,
+                               final ResourceResolverFactory factory,
                                final String startPath,
                                final String mountPrefix,
                                final ServiceTracker eventAdminTracker)
-    throws RepositoryException {
+    throws LoginException, RepositoryException {
         this.workspaceName = workspaceName;
-        this.session = repository.loginAdministrative(workspaceName);
-        this.resolver = factory.getResourceResolver(this.session);
+        Map<String,Object> authInfo = new HashMap<String,Object>();
+        authInfo.put(JcrResourceConstants.AUTH_INFO_WORKSPACE, workspaceName);
+        this.resolver = factory.getAdministrativeResourceResolver(authInfo);
+        this.session = resolver.adaptTo(Session.class);
         this.startPath = startPath;
         this.eventAdminTracker = eventAdminTracker;
         this.mountPrefix = (mountPrefix.equals("/") ? null : mountPrefix);
@@ -107,7 +112,7 @@ public class JcrResourceListener impleme
         } catch (RepositoryException e) {
             logger.warn("Unable to remove session listener: " + this, e);
         }
-        this.session.logout();
+        this.resolver.close();
     }
 
     /**
@@ -163,14 +168,23 @@ public class JcrResourceListener impleme
         // send events for removed
         for(final String path : removedPaths) {
             final Dictionary<String, String> properties = new Hashtable<String, String>();
-            properties.put(SlingConstants.PROPERTY_PATH, path);
+            properties.put(SlingConstants.PROPERTY_PATH, createWorkspacePath(path));
 
             localEA.postEvent(new org.osgi.service.event.Event(SlingConstants.TOPIC_RESOURCE_REMOVED, properties));
         }
     }
 
+    private String createWorkspacePath(String path) {
+        if (workspaceName == null) {
+            return path;
+        } else {
+            return workspaceName+":"+path;
+        }
+    }
+
     private void sendEvents(final Set<String> paths, final String topic, final EventAdmin localEA) {
-        for(final String path : paths) {
+        for(String path : paths) {
+            path = createWorkspacePath(path);
             Resource resource = this.resolver.getResource(path);
             if ( resource != null ) {
                 // check for nt:file nodes
@@ -191,9 +205,6 @@ public class JcrResourceListener impleme
                 }
                 final Dictionary<String, String> properties = new Hashtable<String, String>();
                 properties.put(SlingConstants.PROPERTY_PATH, resource.getPath());
-                if (workspaceName != null) {
-                    properties.put(JcrResourceConstants.PROPERTY_WORKSPACE, workspaceName);
-                }
                 final String resourceType = resource.getResourceType();
                 if ( resourceType != null ) {
                     properties.put(SlingConstants.PROPERTY_RESOURCE_TYPE, resource.getResourceType());

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver.java Tue Apr 13 19:13:31 2010
@@ -27,6 +27,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.jcr.NamespaceException;
+import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.Value;
@@ -36,6 +37,7 @@ import javax.servlet.http.HttpServletReq
 
 import org.apache.sling.adapter.SlingAdaptable;
 import org.apache.sling.api.SlingException;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.NonExistingResource;
 import org.apache.sling.api.resource.QuerySyntaxException;
 import org.apache.sling.api.resource.Resource;
@@ -43,6 +45,7 @@ import org.apache.sling.api.resource.Res
 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.apache.sling.jcr.resource.JcrResourceUtil;
 import org.apache.sling.jcr.resource.internal.helper.MapEntries;
 import org.apache.sling.jcr.resource.internal.helper.MapEntry;
@@ -90,14 +93,27 @@ public class JcrResourceResolver extends
 
     private final MapEntries resourceMapper;
 
+    private boolean isAdmin;
+
+    private final Map<String, Object> originalAuthInfo;
+
+    private final String defaultWorkspaceName;
+
+    private final Map<String,ResourceResolver> createdResolvers = new HashMap<String,ResourceResolver>();
+
     /** Closed marker. */
     private volatile boolean closed = false;
 
     public JcrResourceResolver(JcrResourceProviderEntry rootProvider,
-            JcrResourceResolverFactoryImpl factory, MapEntries resourceMapper) {
+            JcrResourceResolverFactoryImpl factory, MapEntries resourceMapper,
+            boolean isAdmin, Map<String, Object> originalAuthInfo,
+            String defaultWorkspaceName) {
         this.rootProvider = rootProvider;
         this.factory = factory;
         this.resourceMapper = resourceMapper;
+        this.isAdmin = isAdmin;
+        this.originalAuthInfo = originalAuthInfo;
+        this.defaultWorkspaceName = defaultWorkspaceName;
     }
 
     /**
@@ -107,6 +123,9 @@ public class JcrResourceResolver extends
         if ( !this.closed ) {
             this.closed = true;
             getSession().logout();
+            for (ResourceResolver resolver : createdResolvers.values()) {
+                resolver.close();
+            }
         }
     }
 
@@ -186,7 +205,7 @@ public class JcrResourceResolver extends
                     log.debug("resolve: Returning external redirect");
                     return this.factory.getResourceDecoratorTracker().decorate(
                             new RedirectResource(this, absPath, mappedPath[0],
-                                   mapEntry.getStatus()),
+                                   mapEntry.getStatus()), null,
                              request);
                 }
             }
@@ -281,7 +300,7 @@ public class JcrResourceResolver extends
             log.debug("resolve: Path {} resolves to Resource {}", absPath, res);
         }
 
-        return this.factory.getResourceDecoratorTracker().decorate(res, request);
+        return this.factory.getResourceDecoratorTracker().decorate(res, null, request);
     }
 
     /**
@@ -475,22 +494,47 @@ public class JcrResourceResolver extends
     public Resource getResource(String path) {
         checkClosed();
 
+        if (path.contains(":")) {
+            String[] parts = path.split(":");
+            String workspaceName = parts[0];
+            if (workspaceName.equals(getSession().getWorkspace().getName())) {
+                path = parts[1];
+            } else {
+                try {
+                    ResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
+                    return wsResolver.getResource(parts[1]);
+                } catch (LoginException e) {
+                    // requested a resource in a workspace I don't have access to.
+                    // TODO
+                }
+            }
+        }
+
         // if the path is absolute, normalize . and .. segements and get res
         if (path.startsWith("/")) {
             path = ResourceUtil.normalize(path);
-            final Resource result = (path != null) ? getResourceInternal(path) : null;
+            Resource result = (path != null) ? getResourceInternal(path) : null;
             if ( result != null ) {
-                return this.factory.getResourceDecoratorTracker().decorate(result, null);
+                String workspacePrefix = null;
+                if ( !getSession().getWorkspace().getName().equals(defaultWorkspaceName) ) {
+                    workspacePrefix = getSession().getWorkspace().getName();
+                }
+
+                result = this.factory.getResourceDecoratorTracker().decorate(result, workspacePrefix, null);
+                return result;
             }
             return null;
         }
 
         // otherwise we have to apply the search path
         // (don't use this.getSearchPath() to save a few cycle for not cloning)
-        for (String prefix : factory.getSearchPath()) {
-            Resource res = getResource(prefix + path);
-            if (res != null) {
-                return res;
+        String[] paths = factory.getSearchPath();
+        if (paths != null) {
+            for (String prefix : factory.getSearchPath()) {
+                Resource res = getResource(prefix + path);
+                if (res != null) {
+                    return res;
+                }
             }
         }
 
@@ -516,7 +560,29 @@ public class JcrResourceResolver extends
      */
     public Iterator<Resource> listChildren(Resource parent) {
         checkClosed();
-        return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(),
+        String path = parent.getPath();
+        if (path.contains(":")) {
+            String[] parts = path.split(":");
+            String workspaceName = parts[0];
+            if (workspaceName.equals(getSession().getWorkspace().getName())) {
+                path = parts[1];
+            } else {
+                try {
+                    ResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
+                    return wsResolver.listChildren(parent);
+                } catch (LoginException e) {
+                    // requested a resource in a workspace I don't have access to.
+                    // TODO
+                }
+            }
+        }
+
+        String workspacePrefix = null;
+        if ( !getSession().getWorkspace().getName().equals(defaultWorkspaceName) ) {
+            workspacePrefix = getSession().getWorkspace().getName();
+        }
+
+        return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(), workspacePrefix,
                 rootProvider.listChildren(parent));
     }
 
@@ -531,7 +597,7 @@ public class JcrResourceResolver extends
         try {
             QueryResult res = JcrResourceUtil.query(getSession(), query,
                 language);
-            return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(),
+            return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(), null,
                     new JcrNodeResourceIterator(this, res.getNodes(),
                      factory.getDynamicClassLoader()));
         } catch (javax.jcr.query.InvalidQueryException iqe) {
@@ -615,6 +681,24 @@ public class JcrResourceResolver extends
         return rootProvider.getSession();
     }
 
+    // TODO - add some double-checked locking here.
+    private synchronized ResourceResolver getResolverForWorkspace(String workspaceName) throws LoginException {
+        ResourceResolver wsResolver = createdResolvers.get(workspaceName);
+        if (wsResolver == null) {
+            if (isAdmin) {
+                Map<String,Object> newAuthInfo = new HashMap<String,Object>();
+                newAuthInfo.put(JcrResourceConstants.AUTH_INFO_WORKSPACE, workspaceName);
+                wsResolver = factory.getAdministrativeResourceResolver(newAuthInfo);
+            } else {
+                Map<String,Object> newAuthInfo = new HashMap<String,Object>(originalAuthInfo);
+                newAuthInfo.put(JcrResourceConstants.AUTH_INFO_WORKSPACE, workspaceName);
+                wsResolver = factory.getResourceResolver(newAuthInfo);
+            }
+            createdResolvers.put(workspaceName, wsResolver);
+        }
+        return wsResolver;
+    }
+
     /**
      * Returns a string used for matching map entries against the given request
      * or URI parts.

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java Tue Apr 13 19:13:31 2010
@@ -44,6 +44,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.commons.classloader.DynamicClassLoaderManager;
 import org.apache.sling.commons.osgi.OsgiUtil;
 import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.resource.JcrResourceConstants;
 import org.apache.sling.jcr.resource.JcrResourceResolverFactory;
 import org.apache.sling.jcr.resource.internal.helper.MapEntries;
 import org.apache.sling.jcr.resource.internal.helper.Mapping;
@@ -231,11 +232,7 @@ public class JcrResourceResolverFactoryI
      * @see org.apache.sling.jcr.resource.JcrResourceResolverFactory#getResourceResolver(javax.jcr.Session)
      */
     public ResourceResolver getResourceResolver(Session session) {
-        JcrResourceProviderEntry sessionRoot = new JcrResourceProviderEntry(
-            session, rootProviderEntry,
-            this.getDynamicClassLoader());
-
-        return new JcrResourceResolver(sessionRoot, this, mapEntries);
+        return getResourceResolver(session, true, null);
     }
 
     // ---------- Implementation helpers --------------------------------------
@@ -375,22 +372,27 @@ public class JcrResourceResolverFactoryI
                 e);
         }
 
-        String[] listenerWorkspaces = OsgiUtil.toStringArray(properties.get(PROP_LISTENER_WORKSPACES));
 
         // start observation listener
         try {
-            if (listenerWorkspaces == null) {
-                this.resourceListeners =
-                    Collections.singleton(new JcrResourceListener(this.repository, null, this, "/", "/", this.eventAdminTracker));
-            } else {
-                if (Arrays.asList(listenerWorkspaces).contains(ALL_WORKSPACES)) {
-                    listenerWorkspaces = getAllWorkspaces();
-                }
+            this.resourceListeners = new HashSet<JcrResourceListener>();
+
+            // first - add a listener for the default workspace
+            this.resourceListeners.add(new JcrResourceListener(this.repository, null, this, "/", "/", this.eventAdminTracker));
+
+            // then, iterate through any workspaces which are configured
+            String[] listenerWorkspaces = OsgiUtil.toStringArray(properties.get(PROP_LISTENER_WORKSPACES));
+            if (Arrays.asList(listenerWorkspaces).contains(ALL_WORKSPACES)) {
+                listenerWorkspaces = getAllWorkspaces();
+            }
 
+            if (listenerWorkspaces != null) {
                 this.resourceListeners = new HashSet<JcrResourceListener>(listenerWorkspaces.length);
                 for (String wspName : listenerWorkspaces) {
-                    this.resourceListeners.add(
+                    if (!wspName.equals(this.repository.getDefaultWorkspace())) {
+                        this.resourceListeners.add(
                             new JcrResourceListener(this.repository, wspName, this, "/", "/", this.eventAdminTracker));
+                    }
                 }
             }
         } catch (Exception e) {
@@ -471,7 +473,19 @@ public class JcrResourceResolverFactoryI
         } catch (RepositoryException re) {
             throw getLoginException(re);
         }
-        return this.getResourceResolver(handleSudo(session, authenticationInfo));
+        return this.getResourceResolver(handleSudo(session, authenticationInfo), true, authenticationInfo);
+    }
+
+    /**
+     * Create a new ResourceResolver wrapping a Session object. Carries map of
+     * authentication info in order to create a new resolver as needed.
+     */
+    private ResourceResolver getResourceResolver(Session session, boolean isAdmin, Map<String, Object> authenticationInfo) {
+        JcrResourceProviderEntry sessionRoot = new JcrResourceProviderEntry(
+            session, rootProviderEntry,
+            this.getDynamicClassLoader());
+
+        return new JcrResourceResolver(sessionRoot, this, mapEntries, isAdmin, authenticationInfo, repository.getDefaultWorkspace());
     }
 
     /**
@@ -491,7 +505,7 @@ public class JcrResourceResolverFactoryI
         } catch (RepositoryException re) {
             throw getLoginException(re);
         }
-        return this.getResourceResolver(handleSudo(session, authenticationInfo));
+        return this.getResourceResolver(handleSudo(session, authenticationInfo), false, authenticationInfo);
     }
 
     /**
@@ -534,7 +548,7 @@ public class JcrResourceResolverFactoryI
      */
     private String getWorkspace(final Map<String, Object> authenticationInfo) {
         if ( authenticationInfo != null ) {
-            return (String) authenticationInfo.get("user.jcr.workspace");
+            return (String) authenticationInfo.get(JcrResourceConstants.AUTH_INFO_WORKSPACE);
         }
         return null;
     }

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java Tue Apr 13 19:13:31 2010
@@ -55,8 +55,8 @@ public class ResourceDecoratorTracker {
         }
     }
 
-    /** Decorate a resource. */
-    public Resource decorate(final Resource resource, final HttpServletRequest request) {
+    /** Decorate a resource.  */
+    public Resource decorate(final Resource resource, String workspaceName, final HttpServletRequest request) {
         Resource result = resource;
         final ResourceDecorator[] decorators = this.resourceDecoratorsArray;
         for(final ResourceDecorator decorator : decorators) {
@@ -70,6 +70,9 @@ public class ResourceDecoratorTracker {
                 result = original;
             }
         }
+        if (workspaceName != null) {
+            result = new WorkspaceDecoratedResource(result, workspaceName);
+        }
         return result;
     }
 

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java Tue Apr 13 19:13:31 2010
@@ -29,12 +29,16 @@ public class ResourceIteratorDecorator i
 
     private final ResourceDecoratorTracker tracker;
 
+    private final String workspaceName;
+
     private final Iterator<Resource> iterator;
 
     public ResourceIteratorDecorator(final ResourceDecoratorTracker tracker,
+            final String workspaceName,
             final Iterator<Resource> iterator) {
         this.tracker = tracker;
         this.iterator = iterator;
+        this.workspaceName = workspaceName;
     }
 
     public boolean hasNext() {
@@ -42,7 +46,7 @@ public class ResourceIteratorDecorator i
     }
 
     public Resource next() {
-        return this.tracker.decorate(this.iterator.next(), null);
+        return this.tracker.decorate(this.iterator.next(), workspaceName, null);
     }
 
     public void remove() {

Added: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java?rev=933747&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java (added)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java Tue Apr 13 19:13:31 2010
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.sling.jcr.resource.internal;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+
+/**
+ * Decorated resource which prepends the workspace name to
+ * a delegate resource's path.
+ */
+class WorkspaceDecoratedResource implements Resource {
+
+    private final Resource delegate;
+    private final String workspaceName;
+
+    WorkspaceDecoratedResource(Resource resource, String workspaceName) {
+        this.delegate = resource;
+        this.workspaceName = workspaceName;
+    }
+
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        return delegate.adaptTo(type);
+    }
+
+    public String getPath() {
+        if (workspaceName != null) {
+            return workspaceName + ":" + delegate.getPath();
+        } else {
+            return delegate.getPath();
+        }
+    }
+
+    public ResourceMetadata getResourceMetadata() {
+        return delegate.getResourceMetadata();
+    }
+
+    public ResourceResolver getResourceResolver() {
+        return delegate.getResourceResolver();
+    }
+
+    public String getResourceSuperType() {
+        return delegate.getResourceSuperType();
+    }
+
+    public String getResourceType() {
+        return delegate.getResourceType();
+    }
+
+    public String toString() {
+        return delegate.toString();
+    }
+
+}

Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java Tue Apr 13 19:13:31 2010
@@ -114,7 +114,7 @@ public class ResourceProviderEntry imple
 
         // this will consume slightly more memory but ensures read is fast.
         storageMap.setFast(true);
-        
+
     }
 
     /**

Added: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java?rev=933747&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java (added)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java Tue Apr 13 19:13:31 2010
@@ -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;
+
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import junitx.util.PrivateAccessor;
+
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.commons.testing.jcr.EventHelper;
+import org.apache.sling.commons.testing.jcr.RepositoryTestBase;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Test of JcrResourceListener.
+ */
+public class JcrResourceListenerTest extends RepositoryTestBase {
+    private String createdPath;
+
+    private String pathToDelete;
+
+    private String pathToModify;
+
+    public void testDefaultWorkspace() throws Exception {
+        List<Event> events = generateEvents(null);
+
+        Event event = events.get(0);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_ADDED, event.getTopic());
+        assertEquals(createdPath, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+        event = events.get(1);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_CHANGED, event.getTopic());
+        assertEquals(pathToModify, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+        event = events.get(2);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_REMOVED, event.getTopic());
+        assertEquals(pathToDelete, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+    }
+
+    public void testInWs2() throws Exception {
+        List<Event> events = generateEvents("ws2");
+
+        assertEquals(3, events.size());
+        Event event = events.get(0);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_ADDED, event.getTopic());
+        assertEquals("ws2:" + createdPath, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+        event = events.get(1);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_CHANGED, event.getTopic());
+        assertEquals("ws2:" + pathToModify, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+        event = events.get(2);
+        assertEquals(SlingConstants.TOPIC_RESOURCE_REMOVED, event.getTopic());
+        assertEquals("ws2:" + pathToDelete, event.getProperty(SlingConstants.PROPERTY_PATH));
+
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        try {
+            getSession().getWorkspace().createWorkspace("ws2");
+        } catch (Exception e) {
+            if (!e.getMessage().equals("workspace 'ws2' already exists.")) {
+                throw e;
+            }
+        }
+
+    }
+
+    private static void createNode(Session session, String path) throws RepositoryException {
+        session.getRootNode().addNode(path.substring(1), "nt:unstructured");
+        session.save();
+    }
+
+
+    private void addNodeToDelete(Session session) throws RepositoryException {
+        pathToDelete = createTestPath();
+        createNode(session, pathToDelete);
+
+    }
+
+    private void addNodeToModify(Session session) throws RepositoryException {
+        pathToModify = createTestPath();
+        createNode(session, pathToModify);
+
+    }
+
+    private String createTestPath() {
+        return "/test" + System.currentTimeMillis();
+    }
+
+    private List<Event> generateEvents(String workspaceName) throws Exception {
+        final Session session = getRepository().loginAdministrative(workspaceName);
+
+        final List<Event> events = new ArrayList<Event>();
+
+        addNodeToModify(session);
+        addNodeToDelete(session);
+
+        JcrResourceResolverFactoryImpl factory = new JcrResourceResolverFactoryImpl();
+        PrivateAccessor.setField(factory, "repository", getRepository());
+
+        final EventAdmin mockEA = new EventAdmin() {
+
+            public void postEvent(Event event) {
+                events.add(event);
+            }
+
+            public void sendEvent(Event event) {
+                events.add(event);
+            }
+        };
+        final ServiceTracker tracker = mock(ServiceTracker.class);
+        when(tracker.getService()).thenReturn(mockEA);
+
+        JcrResourceListener listener = new SynchronousJcrResourceListener(getRepository(), workspaceName, factory, "/",
+                "/", tracker);
+
+        createdPath = createTestPath();
+        createNode(session, createdPath);
+
+        Node modified = session.getNode(pathToModify);
+        modified.setProperty("foo", "bar");
+        session.save();
+
+        Node deleted = session.getNode(pathToDelete);
+        deleted.remove();
+        session.save();
+
+        listener.dispose();
+
+        Session newSession = getRepository().loginAdministrative(workspaceName);
+        EventHelper helper = new EventHelper(newSession);
+        helper.waitForEvents(5000);
+        helper.dispose();
+        newSession.logout();
+        session.logout();
+
+        return events;
+    }
+}

Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java?rev=933747&r1=933746&r2=933747&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java Tue Apr 13 19:13:31 2010
@@ -21,12 +21,14 @@ package org.apache.sling.jcr.resource.in
 import java.io.BufferedReader;
 import java.lang.reflect.Field;
 import java.security.Principal;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Locale;
 import java.util.Map;
 
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.Node;
+import javax.jcr.Session;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletInputStream;
 import javax.servlet.http.Cookie;
@@ -61,6 +63,12 @@ public class JcrResourceResolverTest ext
 
     private MapEntries mapEntries;
 
+    private Session ws2Session;
+
+    private ResourceResolver ws2Resolver;
+
+    private Node rootWs2Node;
+
     protected void setUp() throws Exception {
         super.setUp();
         assertTrue(RepositoryUtil.registerNodeType(getSession(),
@@ -128,6 +136,15 @@ public class JcrResourceResolverTest ext
         }
 
         resResolver = resFac.getResourceResolver(session);
+
+        ws2Session = getRepository().loginAdministrative("ws2");
+
+        rootWs2Node = ws2Session.getRootNode().addNode(rootPath.substring(1), "nt:unstructured");
+        ws2Session.save();
+
+        ws2Resolver = resFac.getAdministrativeResourceResolver(Collections.singletonMap(JcrResourceConstants.AUTH_INFO_WORKSPACE, (Object) "ws2"));
+
+
     }
 
     @Override
@@ -140,11 +157,18 @@ public class JcrResourceResolverTest ext
             rootNode.remove();
         }
 
+        if (rootWs2Node != null) {
+            rootWs2Node.remove();
+        }
+
         if (mapRoot != null) {
             mapRoot.remove();
         }
 
         session.save();
+        ws2Session.save();
+
+        ws2Resolver.close();
 
         super.tearDown();
     }
@@ -223,6 +247,40 @@ public class JcrResourceResolverTest ext
         assertNull(res);
     }
 
+    public void testGetResourceFromWs2ViaWs2Resolver() throws Exception {
+        // existing resource
+        Resource res = ws2Resolver.getResource("ws2:" + rootPath);
+        assertNotNull(res);
+        assertEquals("ws2:" + rootPath, res.getPath());
+        assertEquals(rootWs2Node.getPrimaryNodeType().getName(),
+            res.getResourceType());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootWs2Node.isSame(res.adaptTo(Node.class)));
+
+        // missing resource
+        String path = "ws2:" + rootPath + "/missing";
+        res = resResolver.getResource(path);
+        assertNull(res);
+    }
+
+    public void testGetResourceFromWs2ViaDefaultResolver() throws Exception {
+        // existing resource
+        Resource res = resResolver.getResource("ws2:" + rootPath);
+        assertNotNull(res);
+        assertEquals("ws2:" + rootPath, res.getPath());
+        assertEquals(rootWs2Node.getPrimaryNodeType().getName(),
+            res.getResourceType());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootWs2Node.isSame(res.adaptTo(Node.class)));
+
+        // missing resource
+        String path = "ws2:" + rootPath + "/missing";
+        res = resResolver.getResource(path);
+        assertNull(res);
+    }
+
     public void testResolveResource() throws Exception {
         // existing resource
         HttpServletRequest request = new ResourceResolverTestRequest(rootPath);
@@ -903,12 +961,12 @@ public class JcrResourceResolverTest ext
         mapped = resResolver.map(child.getPath());
         assertEquals(path, mapped);
     }
-    
+
     public void testMapURLEscaping() throws Exception {
 
         final String mapHostInternal = "internal.host.com";
         final String mapRootInternal = "/content/internal";
-        
+
         Node internalRedirect = mapRoot.getNode("map/http").addNode(
             mapHostInternal + ".80", "sling:Mapping");
         internalRedirect.setProperty(JcrResourceResolver.PROP_REDIRECT_INTERNAL,
@@ -919,7 +977,7 @@ public class JcrResourceResolverTest ext
 
         final String path = "/sample with spaces";
         final String escapedPath = "/sample%20with%20spaces";
-        
+
         // ---------------------------------------------------------------------
         // internal redirect
 
@@ -937,11 +995,11 @@ public class JcrResourceResolverTest ext
         // => only return path, escaped, because request host/port matches (cut off host part)
         mapped = resResolver.map(new ResourceResolverTestRequest(null, mapHostInternal, -1, rootPath), mapRootInternal + path);
         assertEquals(escapedPath, mapped);
-        
+
         // ---------------------------------------------------------------------
         // no mapping config
         // => return only escaped path
-        
+
         final String unmappedRoot = "/unmappedRoot";
 
         // a) test map(String)
@@ -953,7 +1011,7 @@ public class JcrResourceResolverTest ext
         assertEquals(unmappedRoot + escapedPath, mapped);
 
     }
-    
+
     public void testMapNamespaceMangling() throws Exception {
 
         final String mapHost = "virtual.host.com";

Added: 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=933747&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java (added)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java Tue Apr 13 19:13:31 2010
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.sling.jcr.resource.internal;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.observation.SynchronousEventListener;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * This class is used to ensure that events are handled during the test.
+ *
+ * TODO - Ideally, this wouldn't be necessary, but EventHelper doesn't seem
+ * to be working 100% of the time.
+ *
+ */
+public class SynchronousJcrResourceListener extends JcrResourceListener implements SynchronousEventListener {
+
+    public SynchronousJcrResourceListener(SlingRepository repository, String workspaceName,
+            ResourceResolverFactory factory, String startPath, String mountPrefix, ServiceTracker eventAdminTracker)
+            throws LoginException, RepositoryException {
+        super(repository, workspaceName, factory, startPath, mountPrefix, eventAdminTracker);
+    }
+
+}



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

Posted by Justin Edelson <ju...@gmail.com>.
On 4/14/10 2:22 PM, Carsten Ziegeler wrote:
> Carsten Ziegeler  wrote
>> Justin Edelson  wrote
> 
>>> I think this should just be a config option on
>>> JcrResourceResolverFactoryImpl which bypasses the new code blocks
>>> entirely. The only thing we need to watch out for here is that if you
>>> enable non-default workspace observation, non-default workspace
>>> resolution must be enabled, but this is reasonably simple to deal with.
>> Ok, right - I think the configuration part is no problem.
>> I'll try to add a switch to the code and see how it turns out
>>
> WDYT about using the already available
> "resource.resolver.listener.workspaces" property from the factory?
> 
> If this is set we enable the code, if this is not set, we disable the
> code. Or is it more logical to have a separate boolean option?
Maybe the other way around - replace this property with
"resource.resolver.multiworkspace" which, if true, attaches listeners to
all workspaces. There may be no need to listen to only a subset of
workspaces.

Justin

> 
> Regards
> Carsten
> 


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

Posted by Carsten Ziegeler <cz...@apache.org>.
Carsten Ziegeler  wrote
> Justin Edelson  wrote

>> I think this should just be a config option on
>> JcrResourceResolverFactoryImpl which bypasses the new code blocks
>> entirely. The only thing we need to watch out for here is that if you
>> enable non-default workspace observation, non-default workspace
>> resolution must be enabled, but this is reasonably simple to deal with.
> Ok, right - I think the configuration part is no problem.
> I'll try to add a switch to the code and see how it turns out
> 
WDYT about using the already available
"resource.resolver.listener.workspaces" property from the factory?

If this is set we enable the code, if this is not set, we disable the
code. Or is it more logical to have a separate boolean option?

Regards
Carsten

-- 
Carsten Ziegeler
cziegeler@apache.org

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

Posted by Carsten Ziegeler <cz...@apache.org>.
Justin Edelson  wrote
> Argh. I see the problem now. I had setup code to create the ws2
> workspace in the Listener test, but not in the Resolver test. Fixed in
> r933956.
Cool, thanks!

> Makes sense. This code is not optimized, but I wanted to get something
> committed.
Yes, sure - no problem - that's the way open source works :)
I was just in the middle of performance tests and got it by the changes,
but that's more my fault :)

> Ideally, there's a character which is:
> 1) illegal in a JCR node name
> 2) legal in a URL path
> 
> I just don't know off the top of my head what that would be.
Yepp - I don't have a clue either.

> 
> Barring this, I agree that requiring an absolute path is the right
> solution. If you need to pass a relative path to getResource(), you
> could always specify a search path entry like "ws2:/" in the
> JcrResourceResolverFactoryImpl config. Or use the two-argument form of
> getResource().
Ok, so I guess we can go with the current solution.

>> In addition, I'm wondering if we could make this feature completly
>> optional (maybe by a resource resolver wrapper etc.)? (But I think this
>> is something we can look into later on)
> I think this should just be a config option on
> JcrResourceResolverFactoryImpl which bypasses the new code blocks
> entirely. The only thing we need to watch out for here is that if you
> enable non-default workspace observation, non-default workspace
> resolution must be enabled, but this is reasonably simple to deal with.
Ok, right - I think the configuration part is no problem.
I'll try to add a switch to the code and see how it turns out

Regards
Carsten

> 
> Justin
> 
>>
>> Regards
>> Carsten
>>
>> justin  wrote
>>> Author: justin
>>> Date: Tue Apr 13 19:13:31 2010
>>> New Revision: 933747
>>>
>>> URL: http://svn.apache.org/viewvc?rev=933747&view=rev
>>> Log:
>>> SLING-1447 - committing first pass at workspace names in resource paths
>>>
>>> Added:
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java
>>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
>>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
>>> Modified:
>>>     sling/trunk/bundles/jcr/resource/pom.xml
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java
>>>     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/JcrResourceResolver.java
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java
>>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java
>>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java
>>
> 
> 


-- 
Carsten Ziegeler
cziegeler@apache.org

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

Posted by Justin Edelson <ju...@gmail.com>.
On 4/14/10 8:47 AM, Carsten Ziegeler wrote:
> Hi Justin,
> 
> thanks for the changes as we have discussed them roughly. I'm now more
> happy with the way of handling this :)
Well, that's a start...

> 
> It seems that these changes broke the tests for the jcr resource bundle
> - at least on my machine it is failing as the used second workspace is
> not available.
Argh. I see the problem now. I had setup code to create the ws2
workspace in the Listener test, but not in the Resolver test. Fixed in
r933956.

> 
> I've just committed a change in revision 933928. While I tested your
> changes I noticed a drop in performance of nearly 100% with every
> request (in our environment which does literally a lot during a
> request). Now, it seems that the check for the new path syntax
> [workspace:path] causes trouble in our environment as we have paths with
> a colon somewhere in the middle.
> So I went ahead and changed the check from ":" to ":/" and changed also
> the regex based split to a string substring operation.
> This brought us nearly back to the performace we had before - I
> currently note a drop of roughly 10% though I'm not 100% sure that these
> are caused by these changes. I'll further investigate.
Makes sense. This code is not optimized, but I wanted to get something
committed.

> 
> Anyway, to cut a long story short :) it seems that my initial idea of
> just using the ":" as a separator might cause trouble. One solution is
> to go like I did with the quick changes and require a path to be
> absolute if the workspace prefixed notation is used.
> Or we are searching for a different character to separate the two parts?
Ideally, there's a character which is:
1) illegal in a JCR node name
2) legal in a URL path

I just don't know off the top of my head what that would be.

Barring this, I agree that requiring an absolute path is the right
solution. If you need to pass a relative path to getResource(), you
could always specify a search path entry like "ws2:/" in the
JcrResourceResolverFactoryImpl config. Or use the two-argument form of
getResource().

> 
> In addition, I'm wondering if we could make this feature completly
> optional (maybe by a resource resolver wrapper etc.)? (But I think this
> is something we can look into later on)
I think this should just be a config option on
JcrResourceResolverFactoryImpl which bypasses the new code blocks
entirely. The only thing we need to watch out for here is that if you
enable non-default workspace observation, non-default workspace
resolution must be enabled, but this is reasonably simple to deal with.

Justin

> 
> Regards
> Carsten
> 
> justin  wrote
>> Author: justin
>> Date: Tue Apr 13 19:13:31 2010
>> New Revision: 933747
>>
>> URL: http://svn.apache.org/viewvc?rev=933747&view=rev
>> Log:
>> SLING-1447 - committing first pass at workspace names in resource paths
>>
>> Added:
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java
>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
>> Modified:
>>     sling/trunk/bundles/jcr/resource/pom.xml
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java
>>     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/JcrResourceResolver.java
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java
>>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java
>>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java
> 


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

Posted by Carsten Ziegeler <cz...@apache.org>.
Hi Justin,

thanks for the changes as we have discussed them roughly. I'm now more
happy with the way of handling this :)

It seems that these changes broke the tests for the jcr resource bundle
- at least on my machine it is failing as the used second workspace is
not available.

I've just committed a change in revision 933928. While I tested your
changes I noticed a drop in performance of nearly 100% with every
request (in our environment which does literally a lot during a
request). Now, it seems that the check for the new path syntax
[workspace:path] causes trouble in our environment as we have paths with
a colon somewhere in the middle.
So I went ahead and changed the check from ":" to ":/" and changed also
the regex based split to a string substring operation.
This brought us nearly back to the performace we had before - I
currently note a drop of roughly 10% though I'm not 100% sure that these
are caused by these changes. I'll further investigate.

Anyway, to cut a long story short :) it seems that my initial idea of
just using the ":" as a separator might cause trouble. One solution is
to go like I did with the quick changes and require a path to be
absolute if the workspace prefixed notation is used.
Or we are searching for a different character to separate the two parts?

In addition, I'm wondering if we could make this feature completly
optional (maybe by a resource resolver wrapper etc.)? (But I think this
is something we can look into later on)

Regards
Carsten

justin  wrote
> Author: justin
> Date: Tue Apr 13 19:13:31 2010
> New Revision: 933747
> 
> URL: http://svn.apache.org/viewvc?rev=933747&view=rev
> Log:
> SLING-1447 - committing first pass at workspace names in resource paths
> 
> Added:
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/WorkspaceDecoratedResource.java
>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceListenerTest.java
>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/SynchronousJcrResourceListener.java
> Modified:
>     sling/trunk/bundles/jcr/resource/pom.xml
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/JcrResourceConstants.java
>     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/JcrResourceResolver.java
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceDecoratorTracker.java
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/ResourceIteratorDecorator.java
>     sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry.java
>     sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverTest.java

-- 
Carsten Ziegeler
cziegeler@apache.org