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);
+ }
+
+}