You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:59:33 UTC
[sling-org-apache-sling-resourceresolver] 03/47: SLING-2396 : Add
new resourceresolver project
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.resourceresolver-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
commit e5ad4270ea863099029f45d158d8e93aafdfe18e
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Jun 14 09:52:08 2012 +0000
SLING-2396 : Add new resourceresolver project
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/resourceresolver@1350169 13f79535-47bb-0310-9956-ffa450edef68
---
.../impl/ResourceResolverFactoryImpl.java | 606 +++-----------
.../impl/ResourceResolverImpl.java | 890 ++++++---------------
.../console/ResourceResolverWebConsolePlugin.java | 124 ++-
.../impl/helper/RedirectResource.java | 6 +-
.../impl/helper/ResourceDecoratorTracker.java | 60 +-
.../impl/helper/ResourceIterator.java | 83 +-
.../impl/helper/ResourceIteratorDecorator.java | 17 +-
.../impl/helper/ResourcePathIterator.java | 2 +-
.../resourceresolver/impl/helper/StarResource.java | 47 +-
.../sling/resourceresolver/impl/helper/URI.java | 2 +-
.../resourceresolver/impl/helper/URIException.java | 2 +-
.../resourceresolver/impl/mapping/MapEntries.java | 281 +++----
.../resourceresolver/impl/mapping/MapEntry.java | 132 +--
.../resourceresolver/impl/mapping/Mapping.java | 85 +-
.../impl/tree/ProviderHandler.java | 148 ++--
.../impl/tree/ResourceProviderEntry.java | 267 +++----
.../impl/tree/RootResourceProviderEntry.java | 411 ++++++++--
.../OSGI-INF/metatype/metatype.properties | 78 ++
.../impl/ResourceResolverImplTest.java | 547 +++++++++++++
.../impl/helper/RedirectResourceTest.java | 59 ++
.../impl/helper/ResourcePathIteratorTest.java | 155 ++++
.../impl/helper/SortedProviderListTest.java | 266 ++++++
.../impl/helper/StarResourceTest.java | 50 ++
.../impl/mapping/MapEntryTest.java | 174 ++++
.../impl/tree/ProviderHandlerTest.java | 98 +++
.../impl/tree/ResourceProviderEntryTest.java | 341 ++++++++
26 files changed, 3130 insertions(+), 1801 deletions(-)
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
index 969f280..bf954b2 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryImpl.java
@@ -16,26 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal;
+package org.apache.sling.resourceresolver.impl;
import java.util.ArrayList;
import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.regex.Pattern;
-import javax.jcr.Credentials;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.TreeBidiMap;
+import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.PropertyUnbounded;
@@ -47,52 +40,49 @@ import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceDecorator;
import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
-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;
-import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry;
-import org.apache.sling.jcr.resource.internal.helper.RootResourceProviderEntry;
-import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProviderEntry;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.resourceresolver.impl.console.ResourceResolverWebConsolePlugin;
+import org.apache.sling.resourceresolver.impl.helper.ResourceDecoratorTracker;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.mapping.MapEntries;
+import org.apache.sling.resourceresolver.impl.mapping.Mapping;
+import org.apache.sling.resourceresolver.impl.tree.RootResourceProviderEntry;
import org.osgi.framework.Constants;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.EventAdmin;
-import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The <code>JcrResourceResolverFactoryImpl</code> is the
- * {@link JcrResourceResolverFactory} service providing the following
+ * The <code>ResourceResolverFactoryImpl</code> is the {@link ResourceResolverFactory} service
+ * providing the following
* functionality:
* <ul>
- * <li><code>JcrResourceResolverFactory</code> service
- * <li>Bundle listener to load initial content and manage OCM mapping
- * descriptors provided by bundles.
+ * <li><code>ResourceResolverFactory</code> service
* <li>Fires OSGi EventAdmin events on behalf of internal helper objects
* </ul>
*
- * First attempt of an resource resolver factory implementation.
- * WORK IN PROGRESS - see SLING-1262
+ * TODO : Should we implement modifiable? It would be easy but what about long running resolvers?
*/
-@Component(immediate=true, label="%resource.resolver.name", description="%resource.resolver.description", specVersion="1.1", metatype=true)
-@Service(value={JcrResourceResolverFactory.class, ResourceResolverFactory.class})
+@Component(
+ name = "org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl",
+ label = "%resource.resolver.name",
+ description = "%resource.resolver.description",
+ specVersion = "1.1",
+ metatype = true)
+@Service(value = ResourceResolverFactory.class)
@Properties({
- @Property(name = Constants.SERVICE_DESCRIPTION, value="Sling JcrResourceResolverFactory Implementation"),
- @Property(name = Constants.SERVICE_VENDOR, value="The Apache Software Foundation")
-
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "Apache Sling ResourceResolverFactory Implementation"),
+ @Property(name = Constants.SERVICE_VENDOR, value = "The Apache Software Foundation")
})
@References({
- @Reference(name="ResourceProvider", referenceInterface=ResourceProvider.class, cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC),
- @Reference(name="ResourceDecorator", referenceInterface=ResourceDecorator.class, cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE, policy=ReferencePolicy.DYNAMIC)
-})
-public class JcrResourceResolverFactoryImpl implements
- JcrResourceResolverFactory, ResourceResolverFactory {
+ @Reference(name = "ResourceProvider", referenceInterface = ResourceProvider.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
+ @Reference(name = "ResourceProviderFactory", referenceInterface = ResourceProviderFactory.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC),
+ @Reference(name = "ResourceDecorator", referenceInterface = ResourceDecorator.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) })
+public class ResourceResolverFactoryImpl implements ResourceResolverFactory {
public final static class ResourcePattern {
public final Pattern pattern;
@@ -105,15 +95,7 @@ public class JcrResourceResolverFactoryImpl implements
}
}
- private static final boolean DEFAULT_MULTIWORKSPACE = false;
-
- /**
- * Special value which, if passed to listener.workspaces, will have resource
- * events fired for all workspaces.
- */
- public static final String ALL_WORKSPACES = "*";
-
- @Property(value={"/apps", "/libs" })
+ @Property(value = { "/apps", "/libs" })
public static final String PROP_PATH = "resource.resolver.searchpath";
/**
@@ -121,27 +103,22 @@ public class JcrResourceResolverFactoryImpl implements
* (e.g. <code>jcr:</code> in <code>/home/path/jcr:content</code>) are
* mangled or not.
* <p>
- * Mangling means that any namespace prefix contained in the path is replaced
- * as per the generic substitution pattern <code>/([^:]+):/_$1_/</code>
- * when calling the <code>map</code> method of the resource resolver.
- * Likewise the <code>resolve</code> methods will unmangle such namespace
- * prefixes according to the substituation pattern
- * <code>/_([^_]+)_/$1:/</code>.
+ * Mangling means that any namespace prefix contained in the path is replaced as per the generic
+ * substitution pattern <code>/([^:]+):/_$1_/</code> when calling the <code>map</code> method of
+ * the resource resolver. Likewise the <code>resolve</code> methods will unmangle such namespace
+ * prefixes according to the substituation pattern <code>/_([^_]+)_/$1:/</code>.
* <p>
- * This feature is provided since there may be systems out there in the wild
- * which cannot cope with URLs containing colons, even though they are
- * perfectly valid characters in the path part of URI references with a
- * scheme.
+ * This feature is provided since there may be systems out there in the wild which cannot cope
+ * with URLs containing colons, even though they are perfectly valid characters in the path part
+ * of URI references with a scheme.
* <p>
- * The default value of this property if no configuration is provided is
- * <code>true</code>.
+ * The default value of this property if no configuration is provided is <code>true</code>.
*
*/
- @Property(boolValue=true)
+ @Property(boolValue = true)
private static final String PROP_MANGLE_NAMESPACES = "resource.resolver.manglenamespaces";
-
- @Property(boolValue=true)
+ @Property(boolValue = true)
private static final String PROP_ALLOW_DIRECT = "resource.resolver.allowDirect";
/**
@@ -150,28 +127,22 @@ public class JcrResourceResolverFactoryImpl implements
* multivalue properties at the moment. So we just add a dummy direct
* mapping.
*/
- @Property(value="/:/", unbounded=PropertyUnbounded.ARRAY)
+ @Property(value = "/:/", unbounded = PropertyUnbounded.ARRAY)
private static final String PROP_VIRTUAL = "resource.resolver.virtual";
- @Property(value={"/:/", "/content/:/", "/system/docroot/:/"})
+ @Property(value = { "/:/", "/content/:/", "/system/docroot/:/" })
private static final String PROP_MAPPING = "resource.resolver.mapping";
- @Property(value=MapEntries.DEFAULT_MAP_ROOT)
+ @Property(value = MapEntries.DEFAULT_MAP_ROOT)
private static final String PROP_MAP_LOCATION = "resource.resolver.map.location";
- @Property(boolValue=DEFAULT_MULTIWORKSPACE)
- private static final String PROP_MULTIWORKSPACE = "resource.resolver.multiworkspace";
-
- /** default log */
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- @Reference
- private SlingRepository repository;
+ /** Default logger */
+ private final Logger logger = LoggerFactory.getLogger(getClass());
/** Tracker for the resource decorators. */
private final ResourceDecoratorTracker resourceDecoratorTracker = new ResourceDecoratorTracker();
- // helper for the new JcrResourceResolver
+ // helper for the new ResourceResolver
private MapEntries mapEntries = MapEntries.EMPTY;
/** all mappings */
@@ -189,161 +160,59 @@ public class JcrResourceResolverFactoryImpl implements
// the root location of the /etc/map entries
private String mapRoot;
- private final RootResourceProviderEntry rootProviderEntry;
+ private final RootResourceProviderEntry rootProviderEntry = new RootResourceProviderEntry();
// whether to mangle paths with namespaces or not
private boolean mangleNamespacePrefixes;
- private boolean useMultiWorkspaces;
-
- /** The resource listeners for the observation events. */
- private Set<JcrResourceListener> resourceListeners;
-
- /** The service tracker for the event admin
- */
- private ServiceTracker eventAdminTracker;
-
- /** The dynamic class loader */
- @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policy=ReferencePolicy.DYNAMIC)
- private DynamicClassLoaderManager dynamicClassLoaderManager;
-
- private JcrItemAdapterFactory jcrItemAdapterFactory;
-
- public JcrResourceResolverFactoryImpl() {
- this.rootProviderEntry = new RootResourceProviderEntry();
-
- }
-
- public ResourceDecoratorTracker getResourceDecoratorTracker() {
- return this.resourceDecoratorTracker;
- }
-
- // ---------- JcrResourceResolverFactory -----------------------------------
+ /** Event admin. */
+ private EventAdmin eventAdmin;
- /**
- * Returns a new <code>ResourceResolve</code> for the given session. Note
- * that each call to this method returns a new resource manager instance.
- *
- * @see org.apache.sling.jcr.resource.JcrResourceResolverFactory#getResourceResolver(javax.jcr.Session)
- */
- public ResourceResolver getResourceResolver(Session session) {
- Map<String, Object> authInfo = new HashMap<String, Object>(1);
- authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, session);
- try {
- return getResourceResolver(authInfo);
- } catch (LoginException le) {
- // we don't expect a LoginException here because just a
- // ResourceResolver wrapping the given session is to be created.
- throw new InternalError("Unexpected LoginException");
- }
- }
+ /** The web console plugin. */
+ private ResourceResolverWebConsolePlugin plugin;
// ---------- Resource Resolver Factory ------------------------------------
/**
* @see org.apache.sling.api.resource.ResourceResolverFactory#getAdministrativeResourceResolver(java.util.Map)
*/
- public ResourceResolver getAdministrativeResourceResolver(
- final Map<String, Object> authenticationInfo) throws LoginException {
+ public ResourceResolver getAdministrativeResourceResolver(final Map<String, Object> authenticationInfo) throws LoginException {
return getResourceResolverInternal(authenticationInfo, true);
}
/**
* @see org.apache.sling.api.resource.ResourceResolverFactory#getResourceResolver(java.util.Map)
*/
- public ResourceResolver getResourceResolver(
- final Map<String, Object> authenticationInfo) throws LoginException {
+ public ResourceResolver getResourceResolver(final Map<String, Object> authenticationInfo) throws LoginException {
return getResourceResolverInternal(authenticationInfo, false);
}
+ // ---------- Implementation helpers --------------------------------------
+
/**
- * Create a new ResourceResolver wrapping a Session object. Carries map of
- * authentication info in order to create a new resolver as needed.
+ * Create a new ResourceResolver
+ * @param authenticationInfo The authentication map
+ * @param isAdmin is an administrative resolver requested?
+ * @return A resource resolver
+ * @throws LoginException if login to any of the required resource providers fails.
*/
- private ResourceResolver getResourceResolverInternal(
- final Map<String, Object> authenticationInfo, final boolean isAdmin)
- throws LoginException {
+ private ResourceResolver getResourceResolverInternal(final Map<String, Object> authenticationInfo,
+ final boolean isAdmin)
+ throws LoginException {
+ // create context
+ final ResourceResolverContext ctx = new ResourceResolverContext(isAdmin, authenticationInfo);
- // by default any session used by the resource resolver returned is
- // closed when the resource resolver is closed
- boolean logoutSession = true;
+ // login
+ this.rootProviderEntry.loginToRequiredFactories(ctx);
- // derive the session to be used
- Session session;
- try {
- final String workspace = getWorkspace(authenticationInfo);
- if (isAdmin) {
- // requested admin session to any workspace (or default)
- session = getRepository().loginAdministrative(workspace);
-
- } else {
-
- session = getSession(authenticationInfo);
- if (session == null) {
- // requested non-admin session to any workspace (or default)
- final Credentials credentials = getCredentials(authenticationInfo);
- session = getRepository().login(credentials, workspace);
-
- } else if (workspace != null) {
- // session provided by map; but requested a different
- // workspace impersonate can only change the user not switch
- // the workspace as a workaround we login to the requested
- // workspace with admin and then switch to the provided
- // session's user (if required)
- Session tmpSession = null;
- try {
- tmpSession = getRepository().loginAdministrative(
- workspace);
- if (tmpSession.getUserID().equals(session.getUserID())) {
- session = tmpSession;
- tmpSession = null;
- } else {
- session = tmpSession.impersonate(new SimpleCredentials(
- session.getUserID(), new char[0]));
- }
- } finally {
- if (tmpSession != null) {
- tmpSession.logout();
- }
- }
-
- } else {
- // session provided; no special workspace; just make sure
- // the session is not logged out when the resolver is closed
- logoutSession = false;
- }
- }
- } catch (RepositoryException re) {
- throw getLoginException(re);
- }
-
- session = handleImpersonation(session, authenticationInfo, logoutSession);
-
- final JcrResourceProviderEntry sessionRoot = new JcrResourceProviderEntry(
- session, rootProviderEntry, this.getDynamicClassLoader(),
- useMultiWorkspaces);
-
- if (logoutSession) {
- return new JcrResourceResolver(sessionRoot, this, isAdmin,
- authenticationInfo, useMultiWorkspaces);
- }
-
- return new JcrResourceResolver(sessionRoot, this, isAdmin,
- authenticationInfo, useMultiWorkspaces) {
- protected void closeSession() {
- }
- };
+ return new ResourceResolverImpl(this, ctx);
}
- // ---------- Implementation helpers --------------------------------------
-
- /** Get the dynamic class loader if available */
- ClassLoader getDynamicClassLoader() {
- final DynamicClassLoaderManager dclm = this.dynamicClassLoaderManager;
- if ( dclm != null ) {
- return dclm.getDynamicClassLoader();
- }
- return null;
+ /**
+ * Get the resource decorator tracker.
+ */
+ public ResourceDecoratorTracker getResourceDecoratorTracker() {
+ return this.resourceDecoratorTracker;
}
/**
@@ -360,11 +229,11 @@ public class JcrResourceResolverFactoryImpl implements
return mappings;
}
- String[] getSearchPath() {
+ public String[] getSearchPath() {
return searchPath;
}
- boolean isMangleNamespacePrefixes() {
+ public boolean isMangleNamespacePrefixes() {
return mangleNamespacePrefixes;
}
@@ -373,14 +242,10 @@ public class JcrResourceResolverFactoryImpl implements
return mapRoot;
}
- MapEntries getMapEntries() {
+ public MapEntries getMapEntries() {
return mapEntries;
}
- String getDefaultWorkspaceName() {
- return this.repository.getDefaultWorkspace();
- }
-
/**
* Getter for rootProviderEntry, making it easier to extend
* JcrResourceResolverFactoryImpl. See <a
@@ -388,41 +253,38 @@ public class JcrResourceResolverFactoryImpl implements
*
* @return Our rootProviderEntry
*/
- protected ResourceProviderEntry getRootProviderEntry() {
+ protected RootResourceProviderEntry getRootProviderEntry() {
return rootProviderEntry;
}
// ---------- SCR Integration ---------------------------------------------
/** Activates this component, called by SCR before registering as a service */
+ @Activate
protected void activate(final ComponentContext componentContext) {
- // setup tracker first as this is used in the bind/unbind methods
- this.eventAdminTracker = new ServiceTracker(componentContext.getBundleContext(),
- EventAdmin.class.getName(), null);
- this.eventAdminTracker.open();
-
+ this.rootProviderEntry.setEventAdmin(this.eventAdmin);
final Dictionary<?, ?> properties = componentContext.getProperties();
- BidiMap virtuals = new TreeBidiMap();
- String[] virtualList = OsgiUtil.toStringArray(properties.get(PROP_VIRTUAL));
+ final BidiMap virtuals = new TreeBidiMap();
+ final String[] virtualList = PropertiesUtil.toStringArray(properties.get(PROP_VIRTUAL));
for (int i = 0; virtualList != null && i < virtualList.length; i++) {
- String[] parts = Mapping.split(virtualList[i]);
+ final String[] parts = Mapping.split(virtualList[i]);
virtuals.put(parts[0], parts[2]);
}
virtualURLMap = virtuals;
- List<Mapping> maps = new ArrayList<Mapping>();
- String[] mappingList = (String[]) properties.get(PROP_MAPPING);
+ final List<Mapping> maps = new ArrayList<Mapping>();
+ final String[] mappingList = (String[]) properties.get(PROP_MAPPING);
for (int i = 0; mappingList != null && i < mappingList.length; i++) {
maps.add(new Mapping(mappingList[i]));
}
- Mapping[] tmp = maps.toArray(new Mapping[maps.size()]);
+ final Mapping[] tmp = maps.toArray(new Mapping[maps.size()]);
// check whether direct mappings are allowed
- Boolean directProp = (Boolean) properties.get(PROP_ALLOW_DIRECT);
+ final Boolean directProp = (Boolean) properties.get(PROP_ALLOW_DIRECT);
allowDirect = (directProp != null) ? directProp.booleanValue() : true;
if (allowDirect) {
- Mapping[] tmp2 = new Mapping[tmp.length + 1];
+ final Mapping[] tmp2 = new Mapping[tmp.length + 1];
tmp2[0] = Mapping.DIRECT;
System.arraycopy(tmp, 0, tmp2, 1, tmp.length);
mappings = tmp2;
@@ -431,7 +293,7 @@ public class JcrResourceResolverFactoryImpl implements
}
// from configuration if available
- searchPath = OsgiUtil.toStringArray(properties.get(PROP_PATH));
+ searchPath = PropertiesUtil.toStringArray(properties.get(PROP_PATH));
if (searchPath != null && searchPath.length > 0) {
for (int i = 0; i < searchPath.length; i++) {
// ensure leading slash
@@ -449,67 +311,33 @@ public class JcrResourceResolverFactoryImpl implements
}
// namespace mangling
- mangleNamespacePrefixes = OsgiUtil.toBoolean(
- properties.get(PROP_MANGLE_NAMESPACES), false);
+ mangleNamespacePrefixes = PropertiesUtil.toBoolean(properties.get(PROP_MANGLE_NAMESPACES), false);
// the root of the resolver mappings
- mapRoot = OsgiUtil.toString(properties.get(PROP_MAP_LOCATION),
- MapEntries.DEFAULT_MAP_ROOT);
+ mapRoot = PropertiesUtil.toString(properties.get(PROP_MAP_LOCATION), MapEntries.DEFAULT_MAP_ROOT);
// set up the map entries from configuration
try {
- mapEntries = new MapEntries(this, componentContext.getBundleContext(), this.eventAdminTracker);
- } catch (Exception e) {
- log.error(
- "activate: Cannot access repository, failed setting up Mapping Support",
- e);
- }
-
-
- // start observation listener
- try {
- this.resourceListeners = new HashSet<JcrResourceListener>();
-
- // first - add a listener for the default workspace
- this.resourceListeners.add(new JcrResourceListener(null, this, "/", "/", this.eventAdminTracker));
-
- // check if multi workspace support is enabled
- this.useMultiWorkspaces = OsgiUtil.toBoolean(properties.get(PROP_MULTIWORKSPACE), DEFAULT_MULTIWORKSPACE);
- if (this.useMultiWorkspaces) {
- final String[] listenerWorkspaces = getAllWorkspaces();
- for (final String wspName : listenerWorkspaces) {
- if (!wspName.equals(this.repository.getDefaultWorkspace())) {
- this.resourceListeners.add(
- new JcrResourceListener(wspName, this, "/", "/", this.eventAdminTracker));
- }
- }
- }
- } catch (Exception e) {
- log.error(
- "activate: Cannot create resource listener; resource events for JCR resources will be disabled.",
- e);
+ mapEntries = new MapEntries(this, componentContext.getBundleContext(), this.eventAdmin);
+ } catch (final Exception e) {
+ logger.error("activate: Cannot access repository, failed setting up Mapping Support", e);
}
try {
- plugin = new JcrResourceResolverWebConsolePlugin(componentContext.getBundleContext(), this);
- } catch (Throwable ignore) {
- // an exception here propably means the web console plugin is not available
- log.debug(
- "activate: unable to setup web console plugin.", ignore);
+ plugin = new ResourceResolverWebConsolePlugin(componentContext.getBundleContext(), this);
+ } catch (final Throwable ignore) {
+ // an exception here propably means the web console plugin is not
+ // available
+ logger.debug("activate: unable to setup web console plugin.", ignore);
}
-
- jcrItemAdapterFactory = new JcrItemAdapterFactory(componentContext.getBundleContext(), this);
}
- private JcrResourceResolverWebConsolePlugin plugin;
-
- /** Deativates this component, called by SCR to take out of service */
- protected void deactivate(final ComponentContext componentContext) {
- if (jcrItemAdapterFactory != null) {
- jcrItemAdapterFactory.dispose();
- jcrItemAdapterFactory = null;
- }
-
+ /**
+ * Deativates this component (called by SCR to take out of service)
+ */
+ @Deactivate
+ protected void deactivate() {
+ this.rootProviderEntry.setEventAdmin(null);
if (plugin != null) {
plugin.dispose();
plugin = null;
@@ -519,240 +347,48 @@ public class JcrResourceResolverFactoryImpl implements
mapEntries.dispose();
mapEntries = MapEntries.EMPTY;
}
- if ( this.eventAdminTracker != null ) {
- this.eventAdminTracker.close();
- this.eventAdminTracker = null;
- }
- if ( this.resourceListeners != null && !this.resourceListeners.isEmpty() ) {
- for ( JcrResourceListener resourceListener : this.resourceListeners ) {
- resourceListener.dispose();
- }
- this.resourceListeners = null;
- }
this.resourceDecoratorTracker.close();
}
- protected void bindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
- this.rootProviderEntry.bindResourceProvider(provider, props, this.eventAdminTracker);
- }
-
- protected void unbindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
- this.rootProviderEntry.unbindResourceProvider(provider, props, this.eventAdminTracker);
- }
-
- protected void bindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
- this.resourceDecoratorTracker.bindResourceDecorator(decorator, props);
- }
-
- protected void unbindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
- this.resourceDecoratorTracker.unbindResourceDecorator(decorator, props);
- }
-
- // ---------- internal helper ----------------------------------------------
-
- /** Returns the JCR repository used by this factory */
- protected SlingRepository getRepository() {
- return repository;
- }
-
- /**
- * Create a login exception from a repository exception.
- * If the repository exception is a {@link javax.jcr.LoginException}
- * a {@link LoginException} is created with the same information.
- * Otherwise a {@link LoginException} is created which wraps the
- * repository exception.
- * @param re The repository exception.
- * @return The login exception.
- */
- private LoginException getLoginException(final RepositoryException re) {
- if ( re instanceof javax.jcr.LoginException ) {
- return new LoginException(re.getMessage(), re.getCause());
- }
- return new LoginException("Unable to login " + re.getMessage(), re);
- }
-
- /**
- * Get an array of all workspaces.
- */
- private String[] getAllWorkspaces() throws RepositoryException {
- Session session = null;
- try {
- session = repository.loginAdministrative(null);
- return session.getWorkspace().getAccessibleWorkspaceNames();
- } finally {
- if (session != null) {
- session.logout();
- }
- }
- }
-
- /**
- * Returns the session provided as the user.jcr.session property of the
- * <code>authenticationInfo</code> map or <code>null</code> if the
- * property is not contained in the map or is not a <code>javax.jcr.Session</code>.
- * @param authenticationInfo Optional authentication info.
- * @return The user.jcr.session property or <code>null</code>
- */
- private Session getSession(final Map<String, Object> authenticationInfo) {
- if (authenticationInfo != null) {
- final Object sessionObject = authenticationInfo.get(JcrResourceConstants.AUTHENTICATION_INFO_SESSION);
- if (sessionObject instanceof Session) {
- return (Session) sessionObject;
- }
- }
- return null;
- }
-
/**
- * Return the workspace name.
- * If the workspace name is provided, it is returned, otherwise
- * <code>null</code> is returned.
- * @param authenticationInfo Optional authentication info.
- * @return The configured workspace name or <code>null</code>
+ * Bind a resource provider.
*/
- private String getWorkspace(final Map<String, Object> authenticationInfo) {
- if (authenticationInfo != null) {
- final Object workspaceObject = authenticationInfo.get(JcrResourceConstants.AUTHENTICATION_INFO_WORKSPACE);
- if (workspaceObject instanceof String) {
- return (String) workspaceObject;
- }
- }
- return null;
+ protected void bindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+ this.rootProviderEntry.bindResourceProvider(provider, props);
}
/**
- * Return the sudo user information.
- * If the sudo user info is provided, it is returned, otherwise
- * <code>null</code> is returned.
- * @param authenticationInfo Optional authentication info.
- * @return The configured sudo user information or <code>null</code>
+ * Unbind a resource provider.
*/
- private String getSudoUser(final Map<String, Object> authenticationInfo) {
- if (authenticationInfo != null) {
- final Object sudoObject = authenticationInfo.get(ResourceResolverFactory.USER_IMPERSONATION);
- if (sudoObject instanceof String) {
- return (String) sudoObject;
- }
- }
- return null;
+ protected void unbindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+ this.rootProviderEntry.unbindResourceProvider(provider, props);
}
/**
- * Handle the sudo if configured. If the authentication info does not
- * contain a sudo info, this method simply returns the passed in session. If
- * a sudo user info is available, the session is tried to be impersonated.
- * The new impersonated session is returned. The original session is closed.
- * The session is also closed if the impersonation fails.
- *
- * @param session The session.
- * @param authenticationInfo The optional authentication info.
- * @param logoutSession whether to logout the <code>session</code> after
- * impersonation or not.
- * @return The original session or impersonated session.
- * @throws LoginException If something goes wrong.
+ * Bind a resource provider factory.
*/
- private Session handleImpersonation(final Session session,
- final Map<String, Object> authenticationInfo, boolean logoutSession)
- throws LoginException {
- final String sudoUser = getSudoUser(authenticationInfo);
- if (sudoUser != null && !session.getUserID().equals(sudoUser)) {
- try {
- final SimpleCredentials creds = new SimpleCredentials(sudoUser,
- new char[0]);
- copyAttributes(creds, authenticationInfo);
- creds.setAttribute(ResourceResolver.USER_IMPERSONATOR,
- session.getUserID());
- return session.impersonate(creds);
- } catch (RepositoryException re) {
- throw getLoginException(re);
- } finally {
- if (logoutSession) {
- session.logout();
- }
- }
- }
- return session;
+ protected void bindResourceProviderFactory(final ResourceProviderFactory provider, final Map<String, Object> props) {
+ this.rootProviderEntry.bindResourceProviderFactory(provider, props);
}
/**
- * Create a credentials object from the provided authentication info.
- * If no map is provided, <code>null</code> is returned.
- * If a map is provided and contains a credentials object, this object is
- * returned.
- * If a map is provided but does not contain a credentials object nor a
- * user, <code>null</code> is returned.
- * if a map is provided with a user name but without a credentials object
- * a new credentials object is created and all values from the authentication
- * info are added as attributes.
- * @param authenticationInfo Optional authentication info
- * @return A credentials object or <code>null</code>
+ * Unbind a resource provider factory.
*/
- private Credentials getCredentials(final Map<String, Object> authenticationInfo) {
- if (authenticationInfo == null) {
- return null;
- }
-
- final Object credentialsObject = authenticationInfo.get(JcrResourceConstants.AUTHENTICATION_INFO_CREDENTIALS);
- if (credentialsObject instanceof Credentials) {
- return (Credentials) credentialsObject;
- }
-
- // otherwise try to create SimpleCredentials if the userId is set
- final Object userId = authenticationInfo.get(USER);
- if (userId instanceof String) {
- final Object password = authenticationInfo.get(PASSWORD);
- final SimpleCredentials credentials = new SimpleCredentials(
- (String) userId, ((password instanceof char[])
- ? (char[]) password
- : new char[0]));
-
- // add attributes
- copyAttributes(credentials, authenticationInfo);
-
- return credentials;
- }
-
- // no user id (or not a String)
- return null;
+ protected void unbindResourceProviderFactory(final ResourceProviderFactory provider, final Map<String, Object> props) {
+ this.rootProviderEntry.unbindResourceProviderFactory(provider, props);
}
/**
- * Copies the contents of the source map as attributes into the target
- * <code>SimpleCredentials</code> object with the exception of the
- * <code>user.jcr.credentials</code> and <code>user.password</code>
- * attributes to prevent leaking passwords into the JCR Session attributes
- * which might be used for break-in attempts.
- *
- * @param target The <code>SimpleCredentials</code> object whose attributes
- * are to be augmented.
- * @param source The map whose entries (except the ones listed above) are
- * copied as credentials attributes.
+ * Bind a resource decorator.
*/
- private void copyAttributes(final SimpleCredentials target,
- final Map<String, Object> source) {
- final Iterator<Map.Entry<String, Object>> i = source.entrySet().iterator();
- while (i.hasNext()) {
- final Map.Entry<String, Object> current = i.next();
- if (isAttributeVisible(current.getKey())) {
- target.setAttribute(current.getKey(), current.getValue());
- }
- }
+ protected void bindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
+ this.resourceDecoratorTracker.bindResourceDecorator(decorator, props);
}
/**
- * Returns <code>true</code> unless the name is
- * <code>user.jcr.credentials</code> (
- * {@link JcrResourceConstants#AUTHENTICATION_INFO_CREDENTIALS}) or contains
- * the string <code>password</code> as in <code>user.password</code> (
- * {@link org.apache.sling.api.resource.ResourceResolverFactory#PASSWORD})
- *
- * @param name The name to check whether it is visible or not
- * @return <code>true</code> if the name is assumed visible
- * @throws NullPointerException if <code>name</code> is <code>null</code>
+ * Unbind a resource decorator.
*/
- static boolean isAttributeVisible(final String name) {
- return !name.equals(JcrResourceConstants.AUTHENTICATION_INFO_CREDENTIALS)
- && !name.contains("password");
+ protected void unbindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
+ this.resourceDecoratorTracker.unbindResourceDecorator(decorator, props);
}
-
}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
index 1f03d33..a84af79 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
@@ -16,65 +16,52 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal;
+package org.apache.sling.resourceresolver.impl;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.jcr.Credentials;
import javax.jcr.NamespaceException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
import javax.servlet.http.HttpServletRequest;
-import org.apache.sling.adapter.SlingAdaptable;
import org.apache.sling.adapter.annotations.Adaptable;
import org.apache.sling.adapter.annotations.Adapter;
import org.apache.sling.api.SlingException;
+import org.apache.sling.api.adapter.SlingAdaptable;
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;
import org.apache.sling.api.resource.ResourceNotFoundException;
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.api.resource.ResourceWrapper;
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.MapEntry;
-import org.apache.sling.jcr.resource.internal.helper.RedirectResource;
-import org.apache.sling.jcr.resource.internal.helper.ResourceIterator;
-import org.apache.sling.jcr.resource.internal.helper.ResourcePathIterator;
-import org.apache.sling.jcr.resource.internal.helper.URI;
-import org.apache.sling.jcr.resource.internal.helper.URIException;
-import org.apache.sling.jcr.resource.internal.helper.jcr.JcrNodeResourceIterator;
-import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProviderEntry;
-import org.apache.sling.jcr.resource.internal.helper.starresource.StarResource;
+import org.apache.sling.resourceresolver.impl.helper.RedirectResource;
+import org.apache.sling.resourceresolver.impl.helper.ResourceIterator;
+import org.apache.sling.resourceresolver.impl.helper.ResourceIteratorDecorator;
+import org.apache.sling.resourceresolver.impl.helper.ResourcePathIterator;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.helper.StarResource;
+import org.apache.sling.resourceresolver.impl.helper.URI;
+import org.apache.sling.resourceresolver.impl.helper.URIException;
+import org.apache.sling.resourceresolver.impl.mapping.MapEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@Adaptable(adaptableClass=ResourceResolver.class, adapters={ @Adapter(Session.class) })
-public class JcrResourceResolver
- extends SlingAdaptable implements ResourceResolver {
+@Adaptable(adaptableClass = ResourceResolver.class, adapters = { @Adapter(Session.class) })
+public class ResourceResolverImpl extends SlingAdaptable implements ResourceResolver {
- /** default logger */
- private final Logger LOGGER = LoggerFactory.getLogger(JcrResourceResolver.class);
+ /** Default logger */
+ private final Logger logger = LoggerFactory.getLogger(ResourceResolverImpl.class);
private static final String MANGLE_NAMESPACE_IN_SUFFIX = "_";
@@ -88,17 +75,10 @@ public class JcrResourceResolver
private static final String MANGLE_NAMESPACE_OUT = "/([^:/]+):";
- public static final String PROP_REG_EXP = "sling:match";
public static final String PROP_REDIRECT_INTERNAL = "sling:internalRedirect";
- public static final String PROP_ALIAS = "sling:alias";
-
- public static final String PROP_REDIRECT_EXTERNAL = "sling:redirect";
-
- public static final String PROP_REDIRECT_EXTERNAL_STATUS = "sling:status";
-
- public static final String PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS = "sling:redirectStatus";
+ private static final String PROP_ALIAS = "sling:alias";
// The suffix of a resource being a content node of some parent
// such as nt:file. The slash is included to prevent false
@@ -106,87 +86,53 @@ public class JcrResourceResolver
// "xyzjcr:content"
private static final String JCR_CONTENT_LEAF = "/jcr:content";
- @SuppressWarnings("deprecation")
- private static final String DEFAULT_QUERY_LANGUAGE = Query.XPATH;
-
- /** column name for node path */
- private static final String QUERY_COLUMN_PATH = "jcr:path";
-
- /** column name for score value */
- private static final String QUERY_COLUMN_SCORE = "jcr:score";
-
- /** The root provider for the resource tree. */
- private final JcrResourceProviderEntry rootProvider;
-
/** The factory which created this resource resolver. */
- private final JcrResourceResolverFactoryImpl factory;
-
- /** Is this a resource resolver for an admin? */
- private final boolean isAdmin;
-
- /** The original authentication information - this is used for further resource resolver creations. */
- private final Map<String, Object> originalAuthInfo;
-
- /** Resolvers for different workspaces. */
- private Map<String, JcrResourceResolver> createdResolvers;
+ private final ResourceResolverFactoryImpl factory;
/** Closed marker. */
private volatile boolean closed = false;
- /** a resolver with the workspace which was specifically requested via a request attribute. */
- private ResourceResolver requestBoundResolver;
+ /** Resource resolver context. */
+ private final ResourceResolverContext context;
- private final boolean useMultiWorkspaces;
-
- public JcrResourceResolver(final JcrResourceProviderEntry rootProvider,
- final JcrResourceResolverFactoryImpl factory,
- final boolean isAdmin,
- final Map<String, Object> originalAuthInfo,
- boolean useMultiWorkspaces) {
- this.rootProvider = rootProvider;
+ /**
+ * The resource resolver context.
+ */
+ public ResourceResolverImpl(final ResourceResolverFactoryImpl factory, final ResourceResolverContext ctx) {
this.factory = factory;
- this.isAdmin = isAdmin;
- this.originalAuthInfo = originalAuthInfo;
- this.useMultiWorkspaces = useMultiWorkspaces;
+ this.context = ctx;
}
/**
* @see org.apache.sling.api.resource.ResourceResolver#clone(Map)
*/
- public ResourceResolver clone(Map<String, Object> authenticationInfo)
- throws LoginException {
-
+ public ResourceResolver clone(final Map<String, Object> authenticationInfo)
+ throws LoginException {
// ensure resolver is still live
checkClosed();
// create the merged map
- Map<String, Object> newAuthenticationInfo = new HashMap<String, Object>();
- if (originalAuthInfo != null) {
- newAuthenticationInfo.putAll(originalAuthInfo);
+ final Map<String, Object> newAuthenticationInfo = new HashMap<String, Object>();
+ if (this.context.getAuthenticationInfo() != null) {
+ newAuthenticationInfo.putAll(this.context.getAuthenticationInfo());
}
if (authenticationInfo != null) {
newAuthenticationInfo.putAll(authenticationInfo);
}
- // get an administrative resolver if this resolver isAdmin unless
- // credentials and/or user name are present in the credentials and/or
- // a session is present
- if (isAdmin
- && !(newAuthenticationInfo.get(JcrResourceConstants.AUTHENTICATION_INFO_CREDENTIALS) instanceof Credentials)
- && !(newAuthenticationInfo.get(JcrResourceConstants.AUTHENTICATION_INFO_SESSION) instanceof Session)
- && !(newAuthenticationInfo.get(ResourceResolverFactory.USER) instanceof String)) {
- return factory.getAdministrativeResourceResolver(newAuthenticationInfo);
- }
+ // create new context
+ final ResourceResolverContext newContext = new ResourceResolverContext(this.context.isAdmin(), newAuthenticationInfo);
+ this.factory.getRootProviderEntry().loginToRequiredFactories(newContext);
// create a regular resource resolver
- return factory.getResourceResolver(newAuthenticationInfo);
+ return new ResourceResolverImpl(this.factory, newContext);
}
/**
* @see org.apache.sling.api.resource.ResourceResolver#isLive()
*/
public boolean isLive() {
- return !this.closed && getSession().isLive();
+ return !this.closed && this.context.isLive();
}
/**
@@ -195,46 +141,7 @@ public class JcrResourceResolver
public void close() {
if (!this.closed) {
this.closed = true;
- closeCreatedResolvers();
- closeSession();
- }
- }
-
- /**
- * Closes the session underlying this resource resolver. This method is
- * called by the {@link #close()} method.
- * <p>
- * Extensions can overwrite this method to do other work (or not close the
- * session at all). Handle with care !
- */
- protected void closeSession() {
- try {
- getSession().logout();
- } catch (Throwable t) {
- LOGGER.debug(
- "closeSession: Unexpected problem closing the session; ignoring",
- t);
- }
- }
-
- /**
- * Closes any helper resource resolver created while this resource resolver
- * was used.
- * <p>
- * Extensions can overwrite this method to do other work (or not close the
- * created resource resovlers at all). Handle with care !
- */
- protected void closeCreatedResolvers() {
- if (this.createdResolvers != null) {
- for (final ResourceResolver resolver : createdResolvers.values()) {
- try {
- resolver.close();
- } catch (Throwable t) {
- LOGGER.debug(
- "closeCreatedResolvers: Unexpected problem closing the created resovler "
- + resolver + "; ignoring", t);
- }
- }
+ this.context.close();
}
}
@@ -243,17 +150,19 @@ public class JcrResourceResolver
* cleaned up before it is being collected by the garbage collector because
* it is not referred to any more.
*/
- protected void finalize() {
+ protected void finalize() throws Throwable {
close();
+ super.finalize();
}
/**
* Check if the resource resolver is already closed.
*
- * @throws IllegalStateException If the resolver is already closed
+ * @throws IllegalStateException
+ * If the resolver is already closed
*/
private void checkClosed() {
- if ( this.closed ) {
+ if (this.closed) {
throw new IllegalStateException("Resource resolver is already closed.");
}
}
@@ -265,65 +174,19 @@ public class JcrResourceResolver
*/
public Iterator<String> getAttributeNames() {
checkClosed();
- final Set<String> names = new HashSet<String>();
- names.addAll(Arrays.asList(getSession().getAttributeNames()));
- if (originalAuthInfo != null) {
- names.addAll(originalAuthInfo.keySet());
- }
- return new Iterator<String>() {
- final Iterator<String> keys = names.iterator();
-
- String nextKey = seek();
-
- private String seek() {
- while (keys.hasNext()) {
- final String key = keys.next();
- if (JcrResourceResolverFactoryImpl.isAttributeVisible(key)) {
- return key;
- }
- }
- return null;
- }
-
- public boolean hasNext() {
- return nextKey != null;
- }
-
- public String next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- String toReturn = nextKey;
- nextKey = seek();
- return toReturn;
- }
-
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
- };
+ return this.factory.getRootProviderEntry().getAttributeNames(this.context);
}
/**
* @see org.apache.sling.api.resource.ResourceResolver#getAttribute(String)
*/
- public Object getAttribute(String name) {
+ public Object getAttribute(final String name) {
+ checkClosed();
if (name == null) {
throw new NullPointerException("name");
}
- if (JcrResourceResolverFactoryImpl.isAttributeVisible(name)) {
- final Object sessionAttr = getSession().getAttribute(name);
- if (sessionAttr != null) {
- return sessionAttr;
- }
- if (originalAuthInfo != null) {
- return originalAuthInfo.get(name);
- }
- }
-
- // not a visible attribute
- return null;
+ return this.factory.getRootProviderEntry().getAttribute(this.context, name);
}
// ---------- resolving resources
@@ -331,7 +194,7 @@ public class JcrResourceResolver
/**
* @see org.apache.sling.api.resource.ResourceResolver#resolve(java.lang.String)
*/
- public Resource resolve(String absPath) {
+ public Resource resolve(final String absPath) {
checkClosed();
return resolve(null, absPath);
}
@@ -339,82 +202,40 @@ public class JcrResourceResolver
/**
* @see org.apache.sling.api.resource.ResourceResolver#resolve(javax.servlet.http.HttpServletRequest)
*/
- public Resource resolve(HttpServletRequest request) {
+ @SuppressWarnings("javadoc")
+ public Resource resolve(final HttpServletRequest request) {
checkClosed();
// throws NPE if request is null as required
return resolve(request, request.getPathInfo());
}
/**
- * @see org.apache.sling.api.resource.ResourceResolver#resolve(javax.servlet.http.HttpServletRequest, java.lang.String)
+ * @see org.apache.sling.api.resource.ResourceResolver#resolve(javax.servlet.http.HttpServletRequest,
+ * java.lang.String)
*/
public Resource resolve(final HttpServletRequest request, String absPath) {
checkClosed();
- String workspaceName = null;
-
// make sure abspath is not null and is absolute
if (absPath == null) {
absPath = "/";
} else if (!absPath.startsWith("/")) {
- if (useMultiWorkspaces) {
- final int wsSepPos = absPath.indexOf(":/");
- if (wsSepPos != -1) {
- workspaceName = absPath.substring(0, wsSepPos);
- absPath = absPath.substring(wsSepPos + 1);
- } else {
- absPath = "/" + absPath;
- }
- } else {
- absPath = "/" + absPath;
- }
+ absPath = "/" + absPath;
}
// check for special namespace prefix treatment
absPath = unmangleNamespaces(absPath);
- if (useMultiWorkspaces) {
- if (workspaceName == null) {
- // check for workspace info from request
- workspaceName = (request == null ? null :
- (String)request.getAttribute(ResourceResolver.REQUEST_ATTR_WORKSPACE_INFO));
- }
- if (workspaceName != null && !workspaceName.equals(getSession().getWorkspace().getName())) {
- LOGGER.debug("Delegating resolving to resolver for workspace {}", workspaceName);
- try {
- final ResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
- requestBoundResolver = wsResolver;
- return wsResolver.resolve(request, absPath);
- } catch (LoginException e) {
- // requested a resource in a workspace I don't have access to.
- // we treat this as a not found resource
- LOGGER.debug(
- "resolve: Path {} does not resolve, returning NonExistingResource",
- absPath);
-
- final Resource res = new NonExistingResource(this, absPath);
- // SLING-864: if the path contains a dot we assume this to be
- // the start for any selectors, extension, suffix, which may be
- // used for further request processing.
- int index = absPath.indexOf('.');
- if (index != -1) {
- res.getResourceMetadata().setResolutionPathInfo(absPath.substring(index));
- }
- return this.factory.getResourceDecoratorTracker().decorate(res, workspaceName);
- }
- }
- }
// Assume http://localhost:80 if request is null
String[] realPathList = { absPath };
String requestPath;
if (request != null) {
- requestPath = getMapPath(request.getScheme(),
- request.getServerName(), request.getServerPort(), absPath);
+ requestPath = getMapPath(request.getScheme(), request.getServerName(), request.getServerPort(), absPath);
} else {
requestPath = getMapPath("http", "localhost", 80, absPath);
}
- LOGGER.debug("resolve: Resolving request path {}", requestPath);
+ logger.debug("resolve: Resolving request path {}", requestPath);
// loop while finding internal or external redirect into the
// content out of the virtual host mapping tree
@@ -425,41 +246,36 @@ public class JcrResourceResolver
String[] mappedPath = null;
final Iterator<MapEntry> mapEntriesIterator = this.factory.getMapEntries().getResolveMapsIterator(requestPath);
- while ( mapEntriesIterator.hasNext() ) {
+ while (mapEntriesIterator.hasNext()) {
final MapEntry mapEntry = mapEntriesIterator.next();
mappedPath = mapEntry.replace(requestPath);
if (mappedPath != null) {
- if ( LOGGER.isDebugEnabled() ) {
- LOGGER.debug(
- "resolve: MapEntry {} matches, mapped path is {}",
- mapEntry, Arrays.toString(mappedPath));
+ if (logger.isDebugEnabled()) {
+ logger.debug("resolve: MapEntry {} matches, mapped path is {}", mapEntry, Arrays.toString(mappedPath));
}
if (mapEntry.isInternal()) {
// internal redirect
- LOGGER.debug("resolve: Redirecting internally");
+ logger.debug("resolve: Redirecting internally");
break;
}
// external redirect
- LOGGER.debug("resolve: Returning external redirect");
+ logger.debug("resolve: Returning external redirect");
return this.factory.getResourceDecoratorTracker().decorate(
- new RedirectResource(this, absPath, mappedPath[0],
- mapEntry.getStatus()), workspaceName);
+ new RedirectResource(this, absPath, mappedPath[0], mapEntry.getStatus()));
}
}
// if there is no virtual host based path mapping, abort
// and use the original realPath
if (mappedPath == null) {
- LOGGER.debug(
- "resolve: Request path {} does not match any MapEntry",
- requestPath);
+ logger.debug("resolve: Request path {} does not match any MapEntry", requestPath);
break;
}
// if the mapped path is not an URL, use this path to continue
if (!mappedPath[0].contains("://")) {
- LOGGER.debug("resolve: Mapped path is for resource tree");
+ logger.debug("resolve: Mapped path is for resource tree");
realPathList = mappedPath;
break;
}
@@ -468,13 +284,10 @@ public class JcrResourceResolver
// resolve that URI now, using the URI's path as the real path
try {
final URI uri = new URI(mappedPath[0], false);
- requestPath = getMapPath(uri.getScheme(), uri.getHost(),
- uri.getPort(), uri.getPath());
+ requestPath = getMapPath(uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath());
realPathList = new String[] { uri.getPath() };
- LOGGER.debug(
- "resolve: Mapped path is an URL, using new request path {}",
- requestPath);
+ logger.debug("resolve: Mapped path is an URL, using new request path {}", requestPath);
} catch (final URIException use) {
// TODO: log and fail
throw new ResourceNotFoundException(absPath);
@@ -487,12 +300,11 @@ public class JcrResourceResolver
Resource res = null;
for (int i = 0; res == null && i < realPathList.length; i++) {
- String realPath = realPathList[i];
+ final String realPath = realPathList[i];
// first check whether the requested resource is a StarResource
if (StarResource.appliesTo(realPath)) {
- LOGGER.debug("resolve: Mapped path {} is a Star Resource",
- realPath);
+ logger.debug("resolve: Mapped path {} is a Star Resource", realPath);
res = new StarResource(this, ensureAbsPath(realPath));
} else {
@@ -500,16 +312,14 @@ public class JcrResourceResolver
if (realPath.startsWith("/")) {
// let's check it with a direct access first
- LOGGER.debug("resolve: Try absolute mapped path {}", realPath);
+ logger.debug("resolve: Try absolute mapped path {}", realPath);
res = resolveInternal(realPath);
} else {
- String[] searchPath = getSearchPath();
+ final String[] searchPath = getSearchPath();
for (int spi = 0; res == null && spi < searchPath.length; spi++) {
- LOGGER.debug(
- "resolve: Try relative mapped path with search path entry {}",
- searchPath[spi]);
+ logger.debug("resolve: Try relative mapped path with search path entry {}", searchPath[spi]);
res = resolveInternal(searchPath[spi] + realPath);
}
@@ -520,28 +330,27 @@ public class JcrResourceResolver
// if no resource has been found, use a NonExistingResource
if (res == null) {
- String resourcePath = ensureAbsPath(realPathList[0]);
- LOGGER.debug(
- "resolve: Path {} does not resolve, returning NonExistingResource at {}",
- absPath, resourcePath);
+ final String resourcePath = ensureAbsPath(realPathList[0]);
+ logger.debug("resolve: Path {} does not resolve, returning NonExistingResource at {}", absPath, resourcePath);
res = new NonExistingResource(this, resourcePath);
// SLING-864: if the path contains a dot we assume this to be
// the start for any selectors, extension, suffix, which may be
// used for further request processing.
- int index = resourcePath.indexOf('.');
+ final int index = resourcePath.indexOf('.');
if (index != -1) {
res.getResourceMetadata().setResolutionPathInfo(resourcePath.substring(index));
}
} else {
- LOGGER.debug("resolve: Path {} resolves to Resource {}", absPath, res);
+ logger.debug("resolve: Path {} resolves to Resource {}", absPath, res);
}
- return this.factory.getResourceDecoratorTracker().decorate(res, workspaceName);
+ return this.factory.getResourceDecoratorTracker().decorate(res);
}
/**
* calls map(HttpServletRequest, String) as map(null, resourcePath)
+ *
* @see org.apache.sling.api.resource.ResourceResolver#map(java.lang.String)
*/
public String map(final String resourcePath) {
@@ -550,11 +359,12 @@ public class JcrResourceResolver
}
/**
- * full implementation
- * - apply sling:alias from the resource path
- * - apply /etc/map mappings (inkl. config backwards compat)
- * - return absolute uri if possible
- * @see org.apache.sling.api.resource.ResourceResolver#map(javax.servlet.http.HttpServletRequest, java.lang.String)
+ * full implementation - apply sling:alias from the resource path - apply
+ * /etc/map mappings (inkl. config backwards compat) - return absolute uri
+ * if possible
+ *
+ * @see org.apache.sling.api.resource.ResourceResolver#map(javax.servlet.http.HttpServletRequest,
+ * java.lang.String)
*/
public String map(final HttpServletRequest request, final String resourcePath) {
checkClosed();
@@ -571,83 +381,38 @@ public class JcrResourceResolver
if (fragmentQueryMark >= 0) {
fragmentQuery = resourcePath.substring(fragmentQueryMark);
mappedPath = resourcePath.substring(0, fragmentQueryMark);
- LOGGER.debug("map: Splitting resource path '{}' into '{}' and '{}'",
- new Object[] { resourcePath, mappedPath, fragmentQuery });
+ logger.debug("map: Splitting resource path '{}' into '{}' and '{}'", new Object[] { resourcePath, mappedPath,
+ fragmentQuery });
} else {
fragmentQuery = null;
mappedPath = resourcePath;
}
-
// cut off scheme and host, if the same as requested
final String schemehostport;
final String schemePrefix;
if (request != null) {
- schemehostport = MapEntry.getURI(request.getScheme(),
- request.getServerName(), request.getServerPort(), "/");
+ schemehostport = MapEntry.getURI(request.getScheme(), request.getServerName(), request.getServerPort(), "/");
schemePrefix = request.getScheme().concat("://");
- LOGGER.debug(
- "map: Mapping path {} for {} (at least with scheme prefix {})",
- new Object[] { resourcePath, schemehostport, schemePrefix });
+ logger.debug("map: Mapping path {} for {} (at least with scheme prefix {})", new Object[] { resourcePath,
+ schemehostport, schemePrefix });
} else {
schemehostport = null;
schemePrefix = null;
- LOGGER.debug("map: Mapping path {} for default", resourcePath);
+ logger.debug("map: Mapping path {} for default", resourcePath);
}
- Resource res = null;
- String workspaceName = null;
-
- if (useMultiWorkspaces) {
- final int wsSepPos = mappedPath.indexOf(":/");
- if (wsSepPos != -1) {
- workspaceName = mappedPath.substring(0, wsSepPos);
- if (workspaceName.equals(getSession().getWorkspace().getName())) {
- mappedPath = mappedPath.substring(wsSepPos + 1);
- } else {
- try {
- JcrResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
- mappedPath = mappedPath.substring(wsSepPos + 1);
- res = wsResolver.resolveInternal(mappedPath);
- } catch (LoginException e) {
- // requested a resource in a workspace I don't have access to.
- // we treat this as a not found resource
- return null;
- }
- }
- } else {
- // check for workspace info in request
- workspaceName = (request == null ? null :
- (String)request.getAttribute(ResourceResolver.REQUEST_ATTR_WORKSPACE_INFO));
- if ( workspaceName != null && !workspaceName.equals(getSession().getWorkspace().getName())) {
- LOGGER.debug("Delegating resolving to resolver for workspace {}", workspaceName);
- try {
- JcrResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
- res = wsResolver.resolveInternal(mappedPath);
- } catch (LoginException e) {
- // requested a resource in a workspace I don't have access to.
- // we treat this as a not found resource
- return null;
- }
-
- }
- }
- }
-
- if (res == null) {
- res = resolveInternal(mappedPath);
- }
+ final Resource res = resolveInternal(mappedPath);
if (res != null) {
// keep, what we might have cut off in internal resolution
final String resolutionPathInfo = res.getResourceMetadata().getResolutionPathInfo();
- LOGGER.debug("map: Path maps to resource {} with path info {}", res,
- resolutionPathInfo);
+ logger.debug("map: Path maps to resource {} with path info {}", res, resolutionPathInfo);
// find aliases for segments. we can't walk the parent chain
// since the request session might not have permissions to
@@ -656,9 +421,9 @@ public class JcrResourceResolver
Resource current = res;
String path = res.getPath();
- while ( path != null ) {
+ while (path != null) {
String alias = null;
- if ( current != null && !path.endsWith(JCR_CONTENT_LEAF)) {
+ if (current != null && !path.endsWith(JCR_CONTENT_LEAF)) {
alias = getProperty(current, PROP_ALIAS);
}
if (alias == null || alias.length() == 0) {
@@ -666,9 +431,9 @@ public class JcrResourceResolver
}
names.add(alias);
path = ResourceUtil.getParent(path);
- if ( "/".equals(path) ) {
+ if ("/".equals(path)) {
path = null;
- } else if ( path != null ) {
+ } else if (path != null) {
current = res.getResourceResolver().resolve(path);
}
}
@@ -694,7 +459,7 @@ public class JcrResourceResolver
// and then we have the mapped path to work on
mappedPath = buf.toString();
- LOGGER.debug("map: Alias mapping resolves to path {}", mappedPath);
+ logger.debug("map: Alias mapping resolves to path {}", mappedPath);
}
@@ -703,7 +468,7 @@ public class JcrResourceResolver
final String[] mappedPaths = mapEntry.replace(mappedPath);
if (mappedPaths != null) {
- LOGGER.debug("map: Match for Entry {}", mapEntry);
+ logger.debug("map: Match for Entry {}", mapEntry);
mappedPathIsUrl = !mapEntry.isInternal();
@@ -715,12 +480,9 @@ public class JcrResourceResolver
if (candidate.startsWith(schemehostport)) {
mappedPath = candidate.substring(schemehostport.length() - 1);
mappedPathIsUrl = false;
- LOGGER.debug(
- "map: Found host specific mapping {} resolving to {}",
- candidate, mappedPath);
+ logger.debug("map: Found host specific mapping {} resolving to {}", candidate, mappedPath);
break;
- } else if (candidate.startsWith(schemePrefix)
- && mappedPath == null) {
+ } else if (candidate.startsWith(schemePrefix) && mappedPath == null) {
mappedPath = candidate;
}
}
@@ -736,9 +498,7 @@ public class JcrResourceResolver
}
- LOGGER.debug(
- "resolve: MapEntry {} matches, mapped path is {}",
- mapEntry, mappedPath);
+ logger.debug("resolve: MapEntry {} matches, mapped path is {}", mapEntry, mappedPath);
break;
}
@@ -753,28 +513,26 @@ public class JcrResourceResolver
try {
// use commons-httpclient's URI instead of java.net.URI, as it can
// actually accept *unescaped* URIs, such as the "mappedPath" and
- // return them in proper escaped form, including the path, via toString()
- URI uri = new URI(mappedPath, false);
+ // return them in proper escaped form, including the path, via
+ // toString()
+ final URI uri = new URI(mappedPath, false);
// 1. mangle the namespaces in the path
String path = mangleNamespaces(uri.getPath());
// 2. prepend servlet context path if we have a request
- if (request != null && request.getContextPath() != null
- && request.getContextPath().length() > 0) {
+ if (request != null && request.getContextPath() != null && request.getContextPath().length() > 0) {
path = request.getContextPath().concat(path);
}
// update the path part of the URI
uri.setPath(path);
mappedPath = uri.toString();
- } catch (URIException e) {
- LOGGER.warn("map: Unable to mangle namespaces for " + mappedPath
- + " returning unmangled", e);
+ } catch (final URIException e) {
+ logger.warn("map: Unable to mangle namespaces for " + mappedPath + " returning unmangled", e);
}
- LOGGER.debug("map: Returning URL {} as mapping for path {}",
- mappedPath, resourcePath);
+ logger.debug("map: Returning URL {} as mapping for path {}", mappedPath, resourcePath);
// reappend fragment and/or query
if (fragmentQuery != null) {
@@ -802,36 +560,12 @@ public class JcrResourceResolver
public Resource getResource(String path) {
checkClosed();
- if (useMultiWorkspaces) {
- final int wsSepPos = path.indexOf(":/");
- if (wsSepPos != -1) {
- final String workspaceName = path.substring(0, wsSepPos);
- if (workspaceName.equals(getSession().getWorkspace().getName())) {
- path = path.substring(wsSepPos + 1);
- } else {
- try {
- ResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
- return wsResolver.getResource(path.substring(wsSepPos + 1));
- } catch (LoginException e) {
- // requested a resource in a workspace I don't have access to.
- // we treat this as a not found resource
- return null;
- }
- }
- }
- }
-
// if the path is absolute, normalize . and .. segements and get res
if (path.startsWith("/")) {
path = ResourceUtil.normalize(path);
Resource result = (path != null) ? getResourceInternal(path) : null;
- if ( result != null ) {
- String workspacePrefix = null;
- if ( useMultiWorkspaces && !getSession().getWorkspace().getName().equals(this.factory.getDefaultWorkspaceName()) ) {
- workspacePrefix = getSession().getWorkspace().getName();
- }
-
- result = this.factory.getResourceDecoratorTracker().decorate(result, workspacePrefix);
+ if (result != null) {
+ result = this.factory.getResourceDecoratorTracker().decorate(result);
return result;
}
return null;
@@ -839,10 +573,10 @@ public class JcrResourceResolver
// otherwise we have to apply the search path
// (don't use this.getSearchPath() to save a few cycle for not cloning)
- String[] paths = factory.getSearchPath();
+ final String[] paths = factory.getSearchPath();
if (paths != null) {
- for (String prefix : factory.getSearchPath()) {
- Resource res = getResource(prefix + path);
+ for (final String prefix : factory.getSearchPath()) {
+ final Resource res = getResource(prefix + path);
if (res != null) {
return res;
}
@@ -854,9 +588,10 @@ public class JcrResourceResolver
}
/**
- * @see org.apache.sling.api.resource.ResourceResolver#getResource(org.apache.sling.api.resource.Resource, java.lang.String)
+ * @see org.apache.sling.api.resource.ResourceResolver#getResource(org.apache.sling.api.resource.Resource,
+ * java.lang.String)
*/
- public Resource getResource(Resource base, String path) {
+ public Resource getResource(final Resource base, String path) {
checkClosed();
if (!path.startsWith("/") && base != null) {
@@ -869,137 +604,38 @@ public class JcrResourceResolver
/**
* @see org.apache.sling.api.resource.ResourceResolver#listChildren(org.apache.sling.api.resource.Resource)
*/
- @SuppressWarnings("unchecked")
- public Iterator<Resource> listChildren(Resource parent) {
+ public Iterator<Resource> listChildren(final Resource parent) {
checkClosed();
- final String path = parent.getPath();
- final int wsSepPos = path.indexOf(":/");
- if (wsSepPos != -1) {
- final String workspaceName = path.substring(0, wsSepPos);
- if (!workspaceName.equals(getSession().getWorkspace().getName())) {
- if (useMultiWorkspaces) {
- try {
- ResourceResolver wsResolver = getResolverForWorkspace(workspaceName);
- return wsResolver.listChildren(parent);
- } catch (LoginException e) {
- // requested a resource in a workspace I don't have access to.
- // we treat this as a not found resource
- return Collections.EMPTY_LIST.iterator();
- }
- }
- // this is illegal
- return Collections.EMPTY_LIST.iterator();
- } else if (parent instanceof WorkspaceDecoratedResource) {
- parent = ((WorkspaceDecoratedResource) parent).getResource();
- } else {
- LOGGER.warn("looking for children of workspace path {}, but with an undecorated resource.",
- parent.getPath());
- }
- }
- String workspacePrefix = null;
- if ( useMultiWorkspaces && !getSession().getWorkspace().getName().equals(this.factory.getDefaultWorkspaceName()) ) {
- workspacePrefix = getSession().getWorkspace().getName();
+ if (parent instanceof ResourceWrapper) {
+ return listChildren(((ResourceWrapper) parent).getResource());
}
-
- return new ResourceIteratorDecorator(
- this.factory.getResourceDecoratorTracker(), workspacePrefix,
- new ResourceIterator(parent, rootProvider));
+ return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(),
+ new ResourceIterator(this.context, parent, this.factory.getRootProviderEntry()));
}
// ---------- Querying resources
/**
- * @see org.apache.sling.api.resource.ResourceResolver#findResources(java.lang.String, java.lang.String)
+ * @see org.apache.sling.api.resource.ResourceResolver#findResources(java.lang.String,
+ * java.lang.String)
*/
- public Iterator<Resource> findResources(final String query, final String language)
- throws SlingException {
+ public Iterator<Resource> findResources(final String query, final String language) throws SlingException {
checkClosed();
- try {
- Session session = null;
- String workspaceName = null;
- if (requestBoundResolver != null) {
- session = requestBoundResolver.adaptTo(Session.class);
- workspaceName = session.getWorkspace().getName();
- } else {
- session = getSession();
- }
- final QueryResult res = JcrResourceUtil.query(session, query, language);
- return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(), workspaceName,
- new JcrNodeResourceIterator(this, res.getNodes(), factory.getDynamicClassLoader()));
- } catch (javax.jcr.query.InvalidQueryException iqe) {
- throw new QuerySyntaxException(iqe.getMessage(), query, language, iqe);
- } catch (RepositoryException re) {
- throw new SlingException(re.getMessage(), re);
- }
+
+ return new ResourceIteratorDecorator(this.factory.getResourceDecoratorTracker(),
+ this.factory.getRootProviderEntry().findResources(this.context, this, query, language));
}
/**
- * @see org.apache.sling.api.resource.ResourceResolver#queryResources(java.lang.String, java.lang.String)
+ * @see org.apache.sling.api.resource.ResourceResolver#queryResources(java.lang.String,
+ * java.lang.String)
*/
- public Iterator<Map<String, Object>> queryResources(final String query,
- final String language)
+ public Iterator<Map<String, Object>> queryResources(final String query, final String language)
throws SlingException {
checkClosed();
- final String queryLanguage = isSupportedQueryLanguage(language) ? language : DEFAULT_QUERY_LANGUAGE;
-
- try {
- QueryResult result = JcrResourceUtil.query(adaptTo(Session.class), query,
- queryLanguage);
- final String[] colNames = result.getColumnNames();
- final RowIterator rows = result.getRows();
- return new Iterator<Map<String, Object>>() {
- public boolean hasNext() {
- return rows.hasNext();
- };
-
- public Map<String, Object> next() {
- Map<String, Object> row = new HashMap<String, Object>();
- try {
- Row jcrRow = rows.nextRow();
- boolean didPath = false;
- boolean didScore = false;
- Value[] values = jcrRow.getValues();
- for (int i = 0; i < values.length; i++) {
- Value v = values[i];
- if (v != null) {
- String colName = colNames[i];
- row.put(colName,
- JcrResourceUtil.toJavaObject(values[i]));
- if (colName.equals(QUERY_COLUMN_PATH)) {
- didPath = true;
- }
- if (colName.equals(QUERY_COLUMN_SCORE)) {
- didScore = true;
- }
- }
- }
- if (!didPath) {
- row.put(QUERY_COLUMN_PATH, jcrRow.getPath());
- }
- if (!didScore) {
- row.put(QUERY_COLUMN_SCORE, jcrRow.getScore());
- }
-
- } catch (RepositoryException re) {
- LOGGER.error(
- "queryResources$next: Problem accessing row values",
- re);
- }
- return row;
- }
-
- public void remove() {
- throw new UnsupportedOperationException("remove");
- }
- };
- } catch (javax.jcr.query.InvalidQueryException iqe) {
- throw new QuerySyntaxException(iqe.getMessage(), query, language,
- iqe);
- } catch (RepositoryException re) {
- throw new SlingException(re.getMessage(), re);
- }
+ return this.factory.getRootProviderEntry().queryResources(this.context, query, language);
}
/**
@@ -1007,70 +643,92 @@ public class JcrResourceResolver
*/
public String getUserID() {
checkClosed();
- return getSession().getUserID();
- }
-
- // ---------- Adaptable interface
- /**
- * @see org.apache.sling.adapter.SlingAdaptable#adaptTo(java.lang.Class)
- */
- @SuppressWarnings("unchecked")
- public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
- checkClosed();
- if (type == Session.class) {
- if (requestBoundResolver != null) {
- return (AdapterType) requestBoundResolver.adaptTo(Session.class);
+ // Try auth info first
+ if ( this.context.getAuthenticationInfo() != null ) {
+ final Object impUser = this.context.getAuthenticationInfo().get(ResourceResolverFactory.USER_IMPERSONATION);
+ if ( impUser != null ) {
+ return impUser.toString();
}
- return (AdapterType) getSession();
+ final Object user = this.context.getAuthenticationInfo().get(ResourceResolverFactory.USER);
+ if ( user != null ) {
+ return user.toString();
+ }
+ }
+ // Try session
+ final Session session = this.getSession();
+ if ( session != null ) {
+ return session.getUserID();
+ }
+ // Try attributes
+ final Object impUser = this.getAttribute(ResourceResolverFactory.USER_IMPERSONATION);
+ if ( impUser != null ) {
+ return impUser.toString();
+ }
+ final Object user = this.getAttribute(ResourceResolverFactory.USER);
+ if ( user != null ) {
+ return user.toString();
}
- // fall back to default behaviour
- return super.adaptTo(type);
+ return null;
}
- // ---------- internal
+ /** Cached session object, fetched on demand. */
+ private Session cachedSession;
+ /** Flag indicating if a searching has already been searched. */
+ private boolean searchedSession = false;
/**
- * Returns the JCR Session of the root resource provider which provides
- * access to the repository.
+ * Try to get a session from one of the resource providers.
*/
private Session getSession() {
- return rootProvider.getSession();
+ if ( !this.searchedSession ) {
+ this.searchedSession = true;
+ this.cachedSession = this.factory.getRootProviderEntry().adaptTo(this.context, Session.class);
+ }
+ return this.cachedSession;
}
+ // ---------- Adaptable interface
+
/**
- * Get a resolver for the workspace.
+ * @see org.apache.sling.api.adapter.SlingAdaptable#adaptTo(java.lang.Class)
*/
- private synchronized JcrResourceResolver getResolverForWorkspace(
- final String workspaceName) throws LoginException {
- if (createdResolvers == null) {
- createdResolvers = new HashMap<String, JcrResourceResolver>();
+ @SuppressWarnings("unchecked")
+ public <AdapterType> AdapterType adaptTo(final Class<AdapterType> type) {
+ checkClosed();
+
+ if (type == Session.class) {
+ return (AdapterType) getSession();
}
- JcrResourceResolver wsResolver = createdResolvers.get(workspaceName);
- if (wsResolver == null) {
- final Map<String, Object> newAuthInfo = new HashMap<String, Object>();
- newAuthInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_WORKSPACE,
- workspaceName);
- wsResolver = (JcrResourceResolver) clone(newAuthInfo);
- createdResolvers.put(workspaceName, wsResolver);
+ final AdapterType result = this.factory.getRootProviderEntry().adaptTo(this.context, type);
+ if ( result != null ) {
+ return result;
}
- return wsResolver;
+
+ // fall back to default behaviour
+ return super.adaptTo(type);
}
+ // ---------- internal
+
/**
* Returns a string used for matching map entries against the given request
* or URI parts.
*
- * @param scheme The URI scheme
- * @param host The host name
- * @param port The port number. If this is negative, the default value used
+ * @param scheme
+ * The URI scheme
+ * @param host
+ * The host name
+ * @param port
+ * The port number. If this is negative, the default value used
* is 80 unless the scheme is "https" in which case the default
* value is 443.
- * @param path The (absolute) path
+ * @param path
+ * The (absolute) path
* @return The request path string {scheme}/{host}.{port}{path}.
*/
- public static String getMapPath(String scheme, String host, int port, String path) {
+ private static String getMapPath(final String scheme, final String host, int port, final String path) {
if (port < 0) {
port = ("https".equals(scheme)) ? 443 : 80;
}
@@ -1087,24 +745,24 @@ public class JcrResourceResolver
* This method operates in two steps:
* <ol>
* <li>Check the path directly
- * <li>Drill down the resource tree from the root down to the resource
- * trying to get the child as per the respective path segment or finding a
- * child whose <code>sling:alias</code> property is set to the respective
- * name.
+ * <li>Drill down the resource tree from the root down to the resource trying to get the child
+ * as per the respective path segment or finding a child whose <code>sling:alias</code> property
+ * is set to the respective name.
* </ol>
* <p>
- * If neither mechanism (direct access and drill down) resolves to a
- * resource this method returns <code>null</code>.
+ * If neither mechanism (direct access and drill down) resolves to a resource this method
+ * returns <code>null</code>.
*
- * @param absPath The absolute path of the resource to return.
- * @return The resource found or <code>null</code> if the resource could
- * not be found. The
- * {@link org.apache.sling.api.resource.ResourceMetadata#getResolutionPathInfo() resolution path info}
- * field of the resource returned is set to the part of the
- * <code>absPath</code> which has been cut off by the
- * {@link ResourcePathIterator} to resolve the resource.
+ * @param absPath
+ * The absolute path of the resource to return.
+ * @return The resource found or <code>null</code> if the resource could not
+ * be found. The
+ * {@link org.apache.sling.api.resource.ResourceMetadata#getResolutionPathInfo()
+ * resolution path info} field of the resource returned is set to
+ * the part of the <code>absPath</code> which has been cut off by
+ * the {@link ResourcePathIterator} to resolve the resource.
*/
- private Resource resolveInternal(String absPath) {
+ private Resource resolveInternal(final String absPath) {
Resource resource = null;
String curPath = absPath;
try {
@@ -1113,9 +771,8 @@ public class JcrResourceResolver
curPath = it.next();
resource = getResourceInternal(curPath);
}
- } catch (Exception ex) {
- throw new SlingException("Problem trying " + curPath
- + " for request path " + absPath, ex);
+ } catch (final Exception ex) {
+ throw new SlingException("Problem trying " + curPath + " for request path " + absPath, ex);
}
// SLING-627: set the part cut off from the uriPath as
@@ -1123,22 +780,20 @@ public class JcrResourceResolver
// uriPath = curPath + sling.resolutionPathInfo
if (resource != null) {
- String rpi = absPath.substring(curPath.length());
+ final String rpi = absPath.substring(curPath.length());
resource.getResourceMetadata().setResolutionPathInfo(rpi);
- LOGGER.debug(
- "resolveInternal: Found resource {} with path info {} for {}",
- new Object[] { resource, rpi, absPath });
+ logger.debug("resolveInternal: Found resource {} with path info {} for {}", new Object[] { resource, rpi, absPath });
} else {
// no direct resource found, so we have to drill down into the
// resource tree to find a match
resource = getResourceInternal("/");
- StringBuilder resolutionPath = new StringBuilder();
- StringTokenizer tokener = new StringTokenizer(absPath, "/");
+ final StringBuilder resolutionPath = new StringBuilder();
+ final StringTokenizer tokener = new StringTokenizer(absPath, "/");
while (resource != null && tokener.hasMoreTokens()) {
- String childNameRaw = tokener.nextToken();
+ final String childNameRaw = tokener.nextToken();
Resource nextResource = getChildInternal(resource, childNameRaw);
if (nextResource != null) {
@@ -1149,8 +804,7 @@ public class JcrResourceResolver
} else {
String childName = null;
- ResourcePathIterator rpi = new ResourcePathIterator(
- childNameRaw);
+ final ResourcePathIterator rpi = new ResourcePathIterator(childNameRaw);
while (rpi.hasNext() && nextResource == null) {
childName = rpi.next();
nextResource = getChildInternal(resource, childName);
@@ -1179,24 +833,22 @@ public class JcrResourceResolver
resource.getResourceMetadata().setResolutionPath(path);
resource.getResourceMetadata().setResolutionPathInfo(pathInfo);
- LOGGER.debug(
- "resolveInternal: Found resource {} with path info {} for {}",
- new Object[] { resource, pathInfo, absPath });
+ logger.debug("resolveInternal: Found resource {} with path info {} for {}", new Object[] { resource, pathInfo,
+ absPath });
}
}
return resource;
}
- private Resource getChildInternal(Resource parent, String childName) {
+ private Resource getChildInternal(final Resource parent, final String childName) {
Resource child = getResource(parent, childName);
if (child != null) {
- String alias = getProperty(child, PROP_REDIRECT_INTERNAL);
+ final String alias = getProperty(child, PROP_REDIRECT_INTERNAL);
if (alias != null) {
// TODO: might be a redirect ??
- LOGGER.warn(
- "getChildInternal: Internal redirect to {} for Resource {} is not supported yet, ignoring",
- alias, child);
+ logger.warn("getChildInternal: Internal redirect to {} for Resource {} is not supported yet, ignoring", alias,
+ child);
}
// we have the resource name, continue with the next level
@@ -1205,60 +857,54 @@ public class JcrResourceResolver
// we do not have a child with the exact name, so we look for
// a child, whose alias matches the childName
- Iterator<Resource> children = listChildren(parent);
+ final Iterator<Resource> children = listChildren(parent);
while (children.hasNext()) {
child = children.next();
- if (!child.getPath().endsWith(JCR_CONTENT_LEAF)){
- String[] aliases = getProperty(child, PROP_ALIAS, String[].class);
- if (aliases != null) {
- for (String alias : aliases) {
- if (childName.equals(alias)) {
- LOGGER.debug(
- "getChildInternal: Found Resource {} with alias {} to use",
- child, childName);
- return child;
- }
- }
- }
+ if (!child.getPath().endsWith(JCR_CONTENT_LEAF)) {
+ final String[] aliases = getProperty(child, PROP_ALIAS, String[].class);
+ if (aliases != null) {
+ for (final String alias : aliases) {
+ if (childName.equals(alias)) {
+ logger.debug("getChildInternal: Found Resource {} with alias {} to use", child, childName);
+ return child;
+ }
+ }
+ }
}
}
// no match for the childName found
- LOGGER.debug("getChildInternal: Resource {} has no child {}", parent,
- childName);
+ logger.debug("getChildInternal: Resource {} has no child {}", parent, childName);
return null;
}
/**
- * Creates a JcrNodeResource with the given path if existing
+ * Creates a resource with the given path if existing
*/
- protected Resource getResourceInternal(String path) {
+ private Resource getResourceInternal(final String path) {
- Resource resource = rootProvider.getResource(this, path);
+ final Resource resource = this.factory.getRootProviderEntry().getResource(this.context, this, path);
if (resource != null) {
resource.getResourceMetadata().setResolutionPath(path);
return resource;
}
- LOGGER.debug(
- "getResourceInternal: Cannot resolve path '{}' to a resource", path);
+ logger.debug("getResourceInternal: Cannot resolve path '{}' to a resource", path);
return null;
}
- public String getProperty(Resource res, String propName) {
+ private String getProperty(final Resource res, final String propName) {
return getProperty(res, propName, String.class);
}
- public <Type> Type getProperty(Resource res, String propName,
- Class<Type> type) {
+ private <Type> Type getProperty(final Resource res, final String propName, final Class<Type> type) {
// check the property in the resource itself
- ValueMap props = res.adaptTo(ValueMap.class);
+ final ValueMap props = res.adaptTo(ValueMap.class);
if (props != null) {
Type prop = props.get(propName, type);
if (prop != null) {
- LOGGER.debug("getProperty: Resource {} has property {}={}",
- new Object[] { res, propName, prop });
+ logger.debug("getProperty: Resource {} has property {}={}", new Object[] { res, propName, prop });
return prop;
}
// otherwise, check it in the jcr:content child resource
@@ -1275,12 +921,13 @@ public class JcrResourceResolver
}
/**
- * Returns the <code>path</code> as an absolute path. If the path is
- * already absolute it is returned unmodified (the same instance actually).
- * If the path is relative it is made absolute by prepending the first entry
- * of the {@link #getSearchPath() search path}.
+ * Returns the <code>path</code> as an absolute path. If the path is already
+ * absolute it is returned unmodified (the same instance actually). If the
+ * path is relative it is made absolute by prepending the first entry of the
+ * {@link #getSearchPath() search path}.
*
- * @param path The path to ensure absolute
+ * @param path
+ * The path to ensure absolute
* @return The absolute path as explained above
*/
private String ensureAbsPath(String path) {
@@ -1292,12 +939,12 @@ public class JcrResourceResolver
private String mangleNamespaces(String absPath) {
if (factory.isMangleNamespacePrefixes() && absPath.contains(MANGLE_NAMESPACE_OUT_SUFFIX)) {
- Pattern p = Pattern.compile(MANGLE_NAMESPACE_OUT);
- Matcher m = p.matcher(absPath);
+ final Pattern p = Pattern.compile(MANGLE_NAMESPACE_OUT);
+ final Matcher m = p.matcher(absPath);
- StringBuffer buf = new StringBuffer();
+ final StringBuffer buf = new StringBuffer();
while (m.find()) {
- String replacement = MANGLE_NAMESPACE_IN_PREFIX + m.group(1) + MANGLE_NAMESPACE_IN_SUFFIX;
+ final String replacement = MANGLE_NAMESPACE_IN_PREFIX + m.group(1) + MANGLE_NAMESPACE_IN_SUFFIX;
m.appendReplacement(buf, replacement);
}
@@ -1311,33 +958,33 @@ public class JcrResourceResolver
private String unmangleNamespaces(String absPath) {
if (factory.isMangleNamespacePrefixes() && absPath.contains(MANGLE_NAMESPACE_IN_PREFIX)) {
- Pattern p = Pattern.compile(MANGLE_NAMESPACE_IN);
- Matcher m = p.matcher(absPath);
- StringBuffer buf = new StringBuffer();
+ final Pattern p = Pattern.compile(MANGLE_NAMESPACE_IN);
+ final Matcher m = p.matcher(absPath);
+ final StringBuffer buf = new StringBuffer();
while (m.find()) {
- String namespace = m.group(1);
+ final String namespace = m.group(1);
try {
// throws if "namespace" is not a registered
// namespace prefix
- getSession().getNamespaceURI(namespace);
+ final Session session = getSession();
+ if ( session != null ) {
+ session.getNamespaceURI(namespace);
+ final String replacement = MANGLE_NAMESPACE_OUT_PREFIX + namespace + MANGLE_NAMESPACE_OUT_SUFFIX;
+ m.appendReplacement(buf, replacement);
+ } else {
+ logger.debug("unmangleNamespaces: '{}' is not a prefix, not unmangling", namespace);
+ }
- String replacement = MANGLE_NAMESPACE_OUT_PREFIX
- + namespace + MANGLE_NAMESPACE_OUT_SUFFIX;
- m.appendReplacement(buf, replacement);
- } catch (NamespaceException ne) {
+ } catch (final NamespaceException ne) {
// not a valid prefix
- LOGGER.debug(
- "unmangleNamespaces: '{}' is not a prefix, not unmangling",
- namespace);
+ logger.debug("unmangleNamespaces: '{}' is not a prefix, not unmangling", namespace);
- } catch (RepositoryException re) {
+ } catch (final RepositoryException re) {
- LOGGER.warn(
- "unmangleNamespaces: Problem checking namespace '{}'",
- namespace, re);
+ logger.warn("unmangleNamespaces: Problem checking namespace '{}'", namespace, re);
}
}
@@ -1347,19 +994,4 @@ public class JcrResourceResolver
return absPath;
}
-
- private boolean isSupportedQueryLanguage(String language) {
- try {
- String[] supportedLanguages = adaptTo(Session.class).getWorkspace().
- getQueryManager().getSupportedQueryLanguages();
- for (String lang : supportedLanguages) {
- if (lang.equals(language)) {
- return true;
- }
- }
- } catch (RepositoryException e) {
- LOGGER.error("Unable to discover supported query languages", e);
- }
- return false;
- }
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/console/ResourceResolverWebConsolePlugin.java b/src/main/java/org/apache/sling/resourceresolver/impl/console/ResourceResolverWebConsolePlugin.java
index c1cbd64..aa09acf 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/console/ResourceResolverWebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/console/ResourceResolverWebConsolePlugin.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal;
+package org.apache.sling.resourceresolver.impl.console;
import java.io.IOException;
import java.io.PrintWriter;
@@ -28,25 +28,24 @@ import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
-import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
-import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.request.ResponseUtil;
-import org.apache.sling.jcr.resource.internal.helper.MapEntries;
-import org.apache.sling.jcr.resource.internal.helper.MapEntry;
-import org.apache.sling.jcr.resource.internal.helper.URI;
-import org.apache.sling.jcr.resource.internal.helper.URIException;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.helper.URI;
+import org.apache.sling.resourceresolver.impl.helper.URIException;
+import org.apache.sling.resourceresolver.impl.mapping.MapEntries;
+import org.apache.sling.resourceresolver.impl.mapping.MapEntry;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
-public class JcrResourceResolverWebConsolePlugin extends
- HttpServlet {
+public class ResourceResolverWebConsolePlugin extends HttpServlet {
private static final long serialVersionUID = 0;
@@ -57,29 +56,28 @@ public class JcrResourceResolverWebConsolePlugin extends
private static final String PAR_MSG = "msg";
private static final String PAR_TEST = "test";
- private final transient JcrResourceResolverFactoryImpl resolverFactory;
+ private final transient ResourceResolverFactoryImpl resolverFactory;
private transient ServiceRegistration service;
- JcrResourceResolverWebConsolePlugin(BundleContext context,
- JcrResourceResolverFactoryImpl resolverFactory) {
+ public ResourceResolverWebConsolePlugin(BundleContext context,
+ ResourceResolverFactoryImpl resolverFactory) {
this.resolverFactory = resolverFactory;
Dictionary<String, Object> props = new Hashtable<String, Object>();
props.put(Constants.SERVICE_DESCRIPTION,
- "JCRResourceResolver Web Console Plugin");
+ "Resource Resolver Web Console Plugin");
props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
props.put(Constants.SERVICE_PID, getClass().getName());
props.put("felix.webconsole.label", "jcrresolver");
props.put("felix.webconsole.title", "Sling Resource Resolver");
props.put("felix.webconsole.configprinter.modes", "always");
- service = context.registerService(new String[] {
- "javax.servlet.Servlet" },
- this, props);
+ service = context.registerService(
+ new String[] { "javax.servlet.Servlet" }, this, props);
}
- void dispose() {
+ public void dispose() {
if (service != null) {
service.unregister();
service = null;
@@ -87,11 +85,12 @@ public class JcrResourceResolverWebConsolePlugin extends
}
@Override
- protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
- throws ServletException, IOException {
+ protected void doGet(final HttpServletRequest request,
+ final HttpServletResponse response) throws ServletException,
+ IOException {
final String msg = request.getParameter(PAR_MSG);
final String test;
- if ( msg != null ) {
+ if (msg != null) {
test = request.getParameter(PAR_TEST);
} else {
test = null;
@@ -113,7 +112,8 @@ public class JcrResourceResolverWebConsolePlugin extends
pw.println("<tr class='content'>");
pw.println("<td class='content'>Namespace Mangling</td>");
pw.print("<td class='content' colspan='2'>");
- pw.print(resolverFactory.isMangleNamespacePrefixes() ? "Enabled" : "Disabled");
+ pw.print(resolverFactory.isMangleNamespacePrefixes() ? "Enabled"
+ : "Disabled");
pw.print("</td>");
pw.println("</tr>");
pw.println("<tr class='content'>");
@@ -126,29 +126,29 @@ public class JcrResourceResolverWebConsolePlugin extends
separatorHtml(pw);
titleHtml(
- pw,
- "Configuration Test",
- "To test the configuration, enter an URL or a resource path into " +
- "the field and click 'Resolve' to resolve the URL or click 'Map' " +
- "to map the resource path. To simulate a map call that takes the " +
- "current request into account, provide a full URL whose " +
- "scheme/host/port prefix will then be used as the request " +
- "information. The path passed to map will always be the path part " +
- "of the URL.");
+ pw,
+ "Configuration Test",
+ "To test the configuration, enter an URL or a resource path into "
+ + "the field and click 'Resolve' to resolve the URL or click 'Map' "
+ + "to map the resource path. To simulate a map call that takes the "
+ + "current request into account, provide a full URL whose "
+ + "scheme/host/port prefix will then be used as the request "
+ + "information. The path passed to map will always be the path part "
+ + "of the URL.");
pw.println("<tr class='content'>");
pw.println("<td class='content'>Test</td>");
pw.print("<td class='content' colspan='2'>");
pw.print("<form method='post'>");
pw.print("<input type='text' name='" + ATTR_TEST + "' value='");
- if ( test != null ) {
+ if (test != null) {
pw.print(ResponseUtil.escapeXml(test));
}
pw.println("' class='input' size='50'>");
pw.println(" <input type='submit' name='" + ATTR_SUBMIT
- + "' value='Resolve' class='submit'>");
+ + "' value='Resolve' class='submit'>");
pw.println(" <input type='submit' name='" + ATTR_SUBMIT
- + "' value='Map' class='submit'>");
+ + "' value='Map' class='submit'>");
pw.print("</form>");
pw.print("</td>");
pw.println("</tr>");
@@ -165,18 +165,18 @@ public class JcrResourceResolverWebConsolePlugin extends
separatorHtml(pw);
dumpMapHtml(
- pw,
- "Resolver Map Entries",
- "Lists the entries used by the ResourceResolver.resolve methods to map URLs to Resources",
- mapEntries.getResolveMaps());
+ pw,
+ "Resolver Map Entries",
+ "Lists the entries used by the ResourceResolver.resolve methods to map URLs to Resources",
+ mapEntries.getResolveMaps());
separatorHtml(pw);
dumpMapHtml(
- pw,
- "Mapping Map Entries",
- "Lists the entries used by the ResourceResolver.map methods to map Resource Paths to URLs",
- mapEntries.getMapMaps());
+ pw,
+ "Mapping Map Entries",
+ "Lists the entries used by the ResourceResolver.map methods to map Resource Paths to URLs",
+ mapEntries.getMapMaps());
pw.println("</table>");
@@ -190,15 +190,14 @@ public class JcrResourceResolverWebConsolePlugin extends
String msg = null;
if (test != null && test.length() > 0) {
- Session session = null;
+ ResourceResolver resolver = null;
try {
// prepare the request for the resource resolver
HttpServletRequest helper = new ResolverRequest(request, test);
- // get the resource resolver with an administrative session
- session = resolverFactory.getRepository().loginAdministrative(
- null);
- ResourceResolver resolver = resolverFactory.getResourceResolver(session);
+ // get an administrative resource resolver
+ resolver = resolverFactory
+ .getAdministrativeResourceResolver(null);
// map or resolve as instructed
Object result;
@@ -221,20 +220,22 @@ public class JcrResourceResolverWebConsolePlugin extends
msg = "Test Failure: " + t;
} finally {
- if (session != null) {
- session.logout();
+ if (resolver != null) {
+ resolver.close();
}
}
}
// finally redirect
- final String path = request.getContextPath() + request.getServletPath() + request.getPathInfo();
+ final String path = request.getContextPath() + request.getServletPath()
+ + request.getPathInfo();
final String redirectTo;
- if ( msg == null ) {
+ if (msg == null) {
redirectTo = path;
} else {
- redirectTo = path + '?' + PAR_MSG + '=' + encodeParam(msg) + '&' + PAR_TEST + '=' + encodeParam(test);
+ redirectTo = path + '?' + PAR_MSG + '=' + encodeParam(msg) + '&'
+ + PAR_TEST + '=' + encodeParam(test);
}
response.sendRedirect(redirectTo);
}
@@ -253,17 +254,11 @@ public class JcrResourceResolverWebConsolePlugin extends
public void printConfiguration(PrintWriter pw) {
final MapEntries mapEntries = resolverFactory.getMapEntries();
- dumpMapText(
- pw,
- "Resolver Map Entries",
- mapEntries.getResolveMaps());
+ dumpMapText(pw, "Resolver Map Entries", mapEntries.getResolveMaps());
- separatorText(pw);
+ separatorText(pw);
- dumpMapText(
- pw,
- "Mapping Map Entries",
- mapEntries.getMapMaps());
+ dumpMapText(pw, "Mapping Map Entries", mapEntries.getMapMaps());
}
// ---------- internal
@@ -282,7 +277,7 @@ public class JcrResourceResolverWebConsolePlugin extends
for (MapEntry entry : list) {
pw.println("<tr class='content'>");
pw.println("<td class='content' style='vertical-align: top'>"
- + entry.getPattern() + "</td>");
+ + entry.getPattern() + "</td>");
pw.print("<td class='content' style='vertical-align: top'>");
String[] repls = entry.getRedirect();
@@ -305,13 +300,13 @@ public class JcrResourceResolverWebConsolePlugin extends
private void titleHtml(PrintWriter pw, String title, String description) {
pw.println("<tr class='content'>");
pw.println("<th colspan='3'class='content container'>" + title
- + "</th>");
+ + "</th>");
pw.println("</tr>");
if (description != null) {
pw.println("<tr class='content'>");
pw.println("<td colspan='3'class='content'>" + description
- + "</th>");
+ + "</th>");
pw.println("</tr>");
}
}
@@ -332,8 +327,7 @@ public class JcrResourceResolverWebConsolePlugin extends
for (MapEntry entry : list) {
final List<String> redir = Arrays.asList(entry.getRedirect());
- final String status = entry.isInternal()
- ? "internal"
+ final String status = entry.isInternal() ? "internal"
: "external: " + entry.getStatus();
pw.printf(format, entry.getPattern(), redir, status);
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/RedirectResource.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/RedirectResource.java
index f51768b..43c241b 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/RedirectResource.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/RedirectResource.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.helper;
import java.util.Collections;
import java.util.HashMap;
@@ -45,7 +45,7 @@ public final class RedirectResource extends SyntheticResource {
final String target, final int status) {
super(resolver, path, RT_SLING_REDIRECT);
- HashMap<String, Object> props = new HashMap<String, Object>();
+ final Map<String, Object> props = new HashMap<String, Object>();
props.put(PROP_SLING_TARGET, target);
props.put(PROP_SLING_STATUS, status);
this.values = Collections.unmodifiableMap(props);
@@ -55,7 +55,7 @@ public final class RedirectResource extends SyntheticResource {
* @see org.apache.sling.api.adapter.Adaptable#adaptTo(java.lang.Class)
*/
@SuppressWarnings("unchecked")
- public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ public <AdapterType> AdapterType adaptTo(final Class<AdapterType> type) {
if (type == ValueMap.class) {
return (AdapterType) new ValueMapDecorator(values);
} else if (type == Map.class) {
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java
index ffc6a31..0b6dcef 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceDecoratorTracker.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal;
+package org.apache.sling.resourceresolver.impl.helper;
import java.util.ArrayList;
import java.util.Collections;
@@ -24,15 +24,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
-
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.commons.osgi.OsgiUtil;
+import org.apache.sling.commons.osgi.ServiceUtil;
/**
- * Helper class to track the resource decorators and keep
- * them sorted by their service ranking.
+ * Helper class to track the resource decorators and keep them sorted by their
+ * service ranking.
*/
public class ResourceDecoratorTracker {
@@ -55,38 +53,44 @@ public class ResourceDecoratorTracker {
}
}
- /** Decorate a resource. */
- public Resource decorate(final Resource resource, String workspaceName) {
+ /**
+ * Decorate a resource.
+ */
+ public Resource decorate(final Resource resource) {
Resource result = resource;
final ResourceDecorator[] decorators = this.resourceDecoratorsArray;
- for(final ResourceDecorator decorator : decorators) {
+ for (final ResourceDecorator decorator : decorators) {
final Resource original = result;
result = decorator.decorate(original);
- if ( result == null ) {
+ if (result == null) {
result = original;
}
}
- if (workspaceName != null) {
- result = new WorkspaceDecoratedResource(result, workspaceName);
- }
- return result;
- }
- public ResourceDecorator[] getResourceDecorators() {
- return this.resourceDecoratorsArray;
+ return result;
}
- protected void bindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
+ /**
+ * Bind a resouce decorator.
+ */
+ public void bindResourceDecorator(final ResourceDecorator decorator,
+ final Map<String, Object> props) {
synchronized (this.resourceDecorators) {
- this.resourceDecorators.add(new ResourceDecoratorEntry(decorator, OsgiUtil.getComparableForServiceRanking(props)));
+ this.resourceDecorators.add(new ResourceDecoratorEntry(decorator,
+ ServiceUtil.getComparableForServiceRanking(props)));
Collections.sort(this.resourceDecorators);
updateResourceDecoratorsArray();
}
}
- protected void unbindResourceDecorator(final ResourceDecorator decorator, final Map<String, Object> props) {
+ /**
+ * Unbind a resouce decorator.
+ */
+ public void unbindResourceDecorator(final ResourceDecorator decorator,
+ final Map<String, Object> props) {
synchronized (this.resourceDecorators) {
- final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators.iterator();
+ final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators
+ .iterator();
while (i.hasNext()) {
final ResourceDecoratorEntry current = i.next();
if (current.decorator == decorator) {
@@ -99,15 +103,16 @@ public class ResourceDecoratorTracker {
}
/**
- * Updates the ResourceDecorators array, this method is not thread safe and should only be
- * called from a synchronized block.
+ * Updates the ResourceDecorators array, this method is not thread safe and
+ * should only be called from a synchronized block.
*/
- protected void updateResourceDecoratorsArray() {
+ private void updateResourceDecoratorsArray() {
final ResourceDecorator[] decorators;
if (this.resourceDecorators.size() > 0) {
decorators = new ResourceDecorator[this.resourceDecorators.size()];
int index = 0;
- final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators.iterator();
+ final Iterator<ResourceDecoratorEntry> i = this.resourceDecorators
+ .iterator();
while (i.hasNext()) {
decorators[index] = i.next().decorator;
index++;
@@ -121,7 +126,8 @@ public class ResourceDecoratorTracker {
/**
* Internal class to keep track of the resource decorators.
*/
- private static final class ResourceDecoratorEntry implements Comparable<ResourceDecoratorEntry> {
+ private static final class ResourceDecoratorEntry implements
+ Comparable<ResourceDecoratorEntry> {
final Comparable<Object> comparable;
@@ -133,7 +139,7 @@ public class ResourceDecoratorTracker {
this.decorator = d;
}
- public int compareTo(ResourceDecoratorEntry o) {
+ public int compareTo(final ResourceDecoratorEntry o) {
return comparable.compareTo(o.comparable);
}
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java
index 47eed58..322b5de 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.helper;
import java.util.Arrays;
import java.util.HashMap;
@@ -31,6 +31,9 @@ import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.resourceresolver.impl.tree.ProviderHandler;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderEntry;
+import org.apache.sling.resourceresolver.impl.tree.RootResourceProviderEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -59,13 +62,13 @@ public class ResourceIterator implements Iterator<Resource> {
* tree to collect entries which might provide children for the
* {@link #parentResource}.
*/
- private final ResourceProviderEntry rootProviderEntry;
+ private final RootResourceProviderEntry rootProviderEntry;
/**
* <code>ResourceProvider</code> objects registered as nodes above the
* {@link #parentResource} up to the root of the resource tree
*/
- private final Iterator<ResourceProvider> providers;
+ private final Iterator<ProviderHandler> providers;
/**
* The child {@link ResourceProviderEntry} registered at the node of the
@@ -95,27 +98,31 @@ public class ResourceIterator implements Iterator<Resource> {
* returned. Any delayed entry whose path matches the path of a
* non-synthetic resource will not returned.
*/
- private Map<String, Resource> delayed;
+ private final Map<String, Resource> delayed;
/**
* Set of paths of resources already returned. This is used to prevent
* duplicate return of resources.
*/
- private Set<String> visited;
+ private final Set<String> visited;
/**
* The absolute path prefix of the {@link #parentResource} resource with a
* trailing slash to build the absolute path of child resources.
*/
- private String iteratorPath;
+ private final String iteratorPath;
/**
* Iterator on the map of {@link #delayed} synthetic resources
*/
private Iterator<Resource> delayedIter;
- public ResourceIterator(final Resource parentResource,
- final ResourceProviderEntry rootProviderEntry) {
+ private final ResourceResolverContext resourceResolverContext;
+
+ public ResourceIterator(final ResourceResolverContext ctx,
+ final Resource parentResource,
+ final RootResourceProviderEntry rootProviderEntry) {
+ this.resourceResolverContext = ctx;
this.parentResource = parentResource;
this.rootProviderEntry = rootProviderEntry;
@@ -129,12 +136,12 @@ public class ResourceIterator implements Iterator<Resource> {
// gather the providers in linked set, such that we keep
// the order of addition and make sure we only get one entry
// for each resource provider
- Set<ResourceProvider> providersSet = new LinkedHashSet<ResourceProvider>();
- ResourceProviderEntry atPath = getResourceProviders(path, providersSet);
+ final Set<ProviderHandler> providersSet = new LinkedHashSet<ProviderHandler>();
+ final ResourceProviderEntry atPath = getResourceProviders(path, providersSet);
if (log.isDebugEnabled()) {
- log.debug(" Provider Set for path {} {} ", path,
- Arrays.toString(providersSet.toArray(new ResourceProvider[0])));
+ log.debug(" Provider Set for path {} {} ", path, Arrays
+ .toString(providersSet.toArray(new ProviderHandler[providersSet.size()])));
}
this.iteratorPath = path;
providers = providersSet.iterator();
@@ -153,7 +160,7 @@ public class ResourceIterator implements Iterator<Resource> {
throw new NoSuchElementException();
}
- Resource result = nextResource;
+ final Resource result = nextResource;
nextResource = seek();
log.debug(" Child resource [{}] [{}] ", iteratorPath, result.getPath());
return result;
@@ -166,15 +173,15 @@ public class ResourceIterator implements Iterator<Resource> {
private Resource seek() {
while (delayedIter == null) {
while ((resources == null || !resources.hasNext())
- && providers.hasNext()) {
- ResourceProvider provider = providers.next();
- resources = provider.listChildren(parentResource);
+ && providers.hasNext()) {
+ final ProviderHandler provider = providers.next();
+ resources = provider.listChildren(this.resourceResolverContext, parentResource);
log.debug(" Checking Provider {} ", provider);
}
if (resources != null && resources.hasNext()) {
- Resource res = resources.next();
- String resPath = res.getPath();
+ final Resource res = resources.next();
+ final String resPath = res.getPath();
if (visited.contains(resPath)) {
@@ -207,14 +214,18 @@ public class ResourceIterator implements Iterator<Resource> {
final ResourceProviderEntry rpw = baseEntryValues.next();
final String resPath = iteratorPath + rpw.getPath();
if (!visited.contains(resPath)) {
- final ResourceResolver rr = parentResource.getResourceResolver();
- final Resource res = rpw.getResourceFromProviders(rr,
- resPath);
+ final ResourceResolver rr = parentResource
+ .getResourceResolver();
+ final Resource res = rpw.getResourceFromProviders(this.resourceResolverContext, rr,
+ resPath);
if (res == null) {
if (!delayed.containsKey(resPath)) {
- delayed.put(resPath, new SyntheticResource(rr,
- resPath,
- ResourceProvider.RESOURCE_TYPE_SYNTHETIC));
+ delayed.put(
+ resPath,
+ new SyntheticResource(
+ rr,
+ resPath,
+ ResourceProvider.RESOURCE_TYPE_SYNTHETIC));
}
} else {
// return the real resource immediately, add
@@ -223,7 +234,7 @@ public class ResourceIterator implements Iterator<Resource> {
delayed.remove(resPath);
visited.add(resPath);
log.debug(" B resource {} {}", resPath,
- res.getClass());
+ res.getClass());
return res;
}
}
@@ -242,7 +253,7 @@ public class ResourceIterator implements Iterator<Resource> {
// we exhausted all resource providers with their concrete
// resources. now lets do the delayed (synthetic) resources
- Resource res = delayedIter.hasNext() ? delayedIter.next() : null;
+ final Resource res = delayedIter.hasNext() ? delayedIter.next() : null;
if (res != null) {
log.debug(" D resource {} {}", res.getPath(), res.getClass());
}
@@ -253,26 +264,28 @@ public class ResourceIterator implements Iterator<Resource> {
* Returns all resource providers which provider resources whose prefix is
* the given path.
*
- * @param path The prefix path to match the resource provider roots against
- * @param providers The set of already found resource providers to which any
+ * @param path
+ * The prefix path to match the resource provider roots against
+ * @param providers
+ * The set of already found resource providers to which any
* additional resource providers are added.
* @return The ResourceProviderEntry at the node identified with the path or
* <code>null</code> if there is no entry at the given location
*/
- private ResourceProviderEntry getResourceProviders(String path,
- Set<ResourceProvider> providers) {
+ private ResourceProviderEntry getResourceProviders(final String path,
+ final Set<ProviderHandler> providers) {
// collect providers along the ancestor path segements
- String[] elements = ResourceProviderEntry.split(path, '/');
+ final String[] elements = ResourceProviderEntry.split(path, '/');
ResourceProviderEntry base = rootProviderEntry;
- for (String element : elements) {
+ for (final String element : elements) {
if (base.containsKey(element)) {
base = base.get(element);
if (log.isDebugEnabled()) {
log.debug("Loading from {} {} ", element,
- base.getResourceProviders().length);
+ base.getResourceProviders().length);
}
- for (ResourceProvider rp : base.getResourceProviders()) {
+ for (final ProviderHandler rp : base.getResourceProviders()) {
log.debug("Adding {} for {} ", rp, path);
providers.add(rp);
}
@@ -284,7 +297,7 @@ public class ResourceIterator implements Iterator<Resource> {
}
// add in providers at this node in the tree, ie the root provider
- for (ResourceProvider rp : rootProviderEntry.getResourceProviders()) {
+ for (final ProviderHandler rp : rootProviderEntry.getResourceProviders()) {
log.debug("Loading All at {} ", path);
providers.add(rp);
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIteratorDecorator.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIteratorDecorator.java
index 0f67495..1d2864b 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIteratorDecorator.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIteratorDecorator.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal;
+package org.apache.sling.resourceresolver.impl.helper;
import java.util.Iterator;
@@ -29,26 +29,31 @@ public class ResourceIteratorDecorator implements Iterator<Resource> {
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;
}
+ /**
+ * @see java.util.Iterator#hasNext()
+ */
public boolean hasNext() {
return this.iterator.hasNext();
}
+ /**
+ * @see java.util.Iterator#next()
+ */
public Resource next() {
- return this.tracker.decorate(this.iterator.next(), workspaceName);
+ return this.tracker.decorate(this.iterator.next());
}
+ /**
+ * @see java.util.Iterator#remove()
+ */
public void remove() {
this.iterator.remove();
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIterator.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIterator.java
index c6cc059..17482eb 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIterator.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIterator.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.helper;
import java.util.Iterator;
import java.util.NoSuchElementException;
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/StarResource.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/StarResource.java
index e617b1e..097efcb 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/StarResource.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/StarResource.java
@@ -16,9 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper.starresource;
-
-import java.util.Map;
+package org.apache.sling.resourceresolver.impl.helper;
import org.apache.sling.adapter.annotations.Adaptable;
import org.apache.sling.adapter.annotations.Adapter;
@@ -28,10 +26,10 @@ import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.SyntheticResource;
-import org.apache.sling.api.resource.ValueMap;
-/** Used to provide the equivalent of an empty Node for GET requests
- * to *.something (SLING-344)
+/**
+ * Used to provide the equivalent of an empty Node for GET requests to
+ * *.something (SLING-344)
*/
@Adaptable(adaptableClass = Resource.class, adapters = @Adapter(value = { String.class }))
public class StarResource extends SyntheticResource {
@@ -50,35 +48,39 @@ public class StarResource extends SyntheticResource {
}
}
- /** True if a StarResource should be used for the given request, if
- * a real Resource was not found */
+ /**
+ * True if a StarResource should be used for the given request, if a real
+ * Resource was not found
+ */
public static boolean appliesTo(String path) {
return path.contains(SLASH_STAR) || path.endsWith(SLASH_STAR);
}
/**
* Returns true if the path of the resource ends with the
- * {@link #SLASH_STAR} and therefore should be considered a star
- * resource.
+ * {@link #SLASH_STAR} and therefore should be considered a star resource.
*/
public static boolean isStarResource(Resource res) {
return res.getPath().endsWith(SLASH_STAR);
}
public StarResource(ResourceResolver resourceResolver, String path) {
- super(resourceResolver, getResourceMetadata(path), DEFAULT_RESOURCE_TYPE);
+ super(resourceResolver, getResourceMetadata(path),
+ DEFAULT_RESOURCE_TYPE);
resourceSuperType = UNSET_RESOURCE_SUPER_TYPE;
}
/**
- * Calls {@link ResourceUtil#getResourceSuperType(ResourceResolver, String)} method
- * to dynamically resolve the resource super type of this star resource.
+ * Calls {@link ResourceUtil#getResourceSuperType(ResourceResolver, String)}
+ * method to dynamically resolve the resource super type of this star
+ * resource.
*/
public String getResourceSuperType() {
- // Yes, this isn't how you're supposed to compare Strings, but this is intentional.
+ // Yes, this isn't how you're supposed to compare Strings, but this is
+ // intentional.
if (resourceSuperType == UNSET_RESOURCE_SUPER_TYPE) {
- resourceSuperType = ResourceUtil.getResourceSuperType(this.getResourceResolver(),
- this.getResourceType());
+ resourceSuperType = ResourceUtil.getResourceSuperType(
+ this.getResourceResolver(), this.getResourceType());
}
return resourceSuperType;
}
@@ -86,21 +88,22 @@ public class StarResource extends SyntheticResource {
@Override
@SuppressWarnings("unchecked")
public <Type> Type adaptTo(Class<Type> type) {
- if ( type == String.class ) {
- return (Type)"";
+ if (type == String.class) {
+ return (Type) "";
}
return super.adaptTo(type);
}
/** Get our ResourceMetadata for given path */
static ResourceMetadata getResourceMetadata(String path) {
- ResourceMetadata result = new ResourceMetadata();
+ ResourceMetadata result = new ResourceMetadata();
- // The path is up to /*, what follows is pathInfo
+ // The path is up to /*, what follows is pathInfo
final int index = path.indexOf(SLASH_STAR);
- if(index >= 0) {
+ if (index >= 0) {
result.setResolutionPath(path.substring(0, index) + SLASH_STAR);
- result.setResolutionPathInfo(path.substring(index + SLASH_STAR.length()));
+ result.setResolutionPathInfo(path.substring(index
+ + SLASH_STAR.length()));
} else {
result.setResolutionPath(path);
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/URI.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/URI.java
index 7bdbb8d..67e69b2 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/URI.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/URI.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.helper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/helper/URIException.java b/src/main/java/org/apache/sling/resourceresolver/impl/helper/URIException.java
index 90a15fe..435cc5c 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/helper/URIException.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/helper/URIException.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.helper;
import org.apache.sling.api.SlingException;
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
index 47c0150..dfe3c4b 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.mapping;
import java.net.MalformedURLException;
import java.net.URL;
@@ -48,8 +48,8 @@ import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.jcr.resource.internal.JcrResourceResolver;
-import org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
@@ -57,7 +57,6 @@ import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
-import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -65,6 +64,14 @@ public class MapEntries implements EventHandler {
public static final MapEntries EMPTY = new MapEntries();
+ private static final String PROP_REG_EXP = "sling:match";
+
+ public static final String PROP_REDIRECT_EXTERNAL = "sling:redirect";
+
+ public static final String PROP_REDIRECT_EXTERNAL_STATUS = "sling:status";
+
+ public static final String PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS = "sling:redirectStatus";
+
/** Key for the global list. */
private static final String GLOBAL_LIST_KEY = "*";
@@ -77,7 +84,7 @@ public class MapEntries implements EventHandler {
/** default log */
private final Logger log = LoggerFactory.getLogger(getClass());
- private JcrResourceResolverFactoryImpl factory;
+ private ResourceResolverFactoryImpl factory;
private volatile ResourceResolver resolver;
@@ -91,7 +98,7 @@ public class MapEntries implements EventHandler {
private ServiceRegistration registration;
- private ServiceTracker eventAdminTracker;
+ private EventAdmin eventAdmin;
private final Semaphore initTrigger = new Semaphore(0);
@@ -107,18 +114,16 @@ public class MapEntries implements EventHandler {
this.mapMaps = Collections.<MapEntry> emptyList();
this.vanityTargets = Collections.<String> emptySet();
this.registration = null;
- this.eventAdminTracker = null;
+ this.eventAdmin = null;
}
@SuppressWarnings("unchecked")
- public MapEntries(final JcrResourceResolverFactoryImpl factory,
- final BundleContext bundleContext,
- final ServiceTracker eventAdminTracker)
- throws LoginException {
+ public MapEntries(final ResourceResolverFactoryImpl factory, final BundleContext bundleContext, final EventAdmin eventAdmin)
+ throws LoginException {
this.resolver = factory.getAdministrativeResourceResolver(null);
this.factory = factory;
this.mapRoot = factory.getMapRoot();
- this.eventAdminTracker = eventAdminTracker;
+ this.eventAdmin = eventAdmin;
this.resolveMapsMap = Collections.singletonMap(GLOBAL_LIST_KEY, (List<MapEntry>)Collections.EMPTY_LIST);
this.mapMaps = Collections.<MapEntry> emptyList();
@@ -143,8 +148,7 @@ public class MapEntries implements EventHandler {
}
/**
- * Signals the init method that a the doInit method should be
- * called.
+ * Signals the init method that a the doInit method should be called.
*/
private void triggerInit() {
// only release if there is not one in the queue already
@@ -154,9 +158,9 @@ public class MapEntries implements EventHandler {
}
/**
- * Runs as the method of the update thread. Waits for the triggerInit
- * method to trigger a call to doInit. Terminates when the resolver
- * has been null-ed after having been triggered.
+ * Runs as the method of the update thread. Waits for the triggerInit method
+ * to trigger a call to doInit. Terminates when the resolver has been
+ * null-ed after having been triggered.
*/
void init() {
while (this.resolver != null) {
@@ -171,16 +175,16 @@ public class MapEntries implements EventHandler {
}
/**
- * Actual initializer. Guards itself agains concurrent use by
- * using a ReentrantLock. Does nothing if the resource resolver
- * has already been null-ed.
+ * Actual initializer. Guards itself agains concurrent use by using a
+ * ReentrantLock. Does nothing if the resource resolver has already been
+ * null-ed.
*/
private void doInit() {
this.initializing.lock();
try {
final ResourceResolver resolver = this.resolver;
- final JcrResourceResolverFactoryImpl factory = this.factory;
+ final ResourceResolverFactoryImpl factory = this.factory;
if (resolver == null || factory == null) {
return;
}
@@ -224,19 +228,18 @@ public class MapEntries implements EventHandler {
* Cleans up this class.
*/
public void dispose() {
- if ( this.registration != null ) {
+ if (this.registration != null) {
this.registration.unregister();
this.registration = null;
}
/*
- * Cooperation with doInit: The same lock as used by doInit
- * is acquired thus preventing doInit from running and waiting
- * for a concurrent doInit to terminate.
- * Once the lock has been acquired, the resource resolver is
- * null-ed (thus causing the init to terminate when triggered
- * the right after and prevent the doInit method from doing any
- * thing).
+ * Cooperation with doInit: The same lock as used by doInit is acquired
+ * thus preventing doInit from running and waiting for a concurrent
+ * doInit to terminate. Once the lock has been acquired, the resource
+ * resolver is null-ed (thus causing the init to terminate when
+ * triggered the right after and prevent the doInit method from doing
+ * any thing).
*/
// wait at most 10 seconds for a notifcation during initialization
@@ -274,7 +277,7 @@ public class MapEntries implements EventHandler {
// clear the rest of the fields
this.factory = null;
- this.eventAdminTracker = null;
+ this.eventAdmin = null;
}
/**
@@ -282,7 +285,7 @@ public class MapEntries implements EventHandler {
*/
public List<MapEntry> getResolveMaps() {
final List<MapEntry> entries = new ArrayList<MapEntry>();
- for(final List<MapEntry> list : this.resolveMapsMap.values()) {
+ for (final List<MapEntry> list : this.resolveMapsMap.values()) {
entries.addAll(list);
}
Collections.sort(entries);
@@ -290,16 +293,14 @@ public class MapEntries implements EventHandler {
}
/**
- * Calculate the resolve maps.
- * As the entries have to be sorted by pattern length,
- * we have to create a new list containing all
- * relevant entries.
+ * Calculate the resolve maps. As the entries have to be sorted by pattern
+ * length, we have to create a new list containing all relevant entries.
*/
public Iterator<MapEntry> getResolveMapsIterator(final String requestPath) {
String key = null;
final int firstIndex = requestPath.indexOf('/');
final int secondIndex = requestPath.indexOf('/', firstIndex + 1);
- if ( secondIndex != -1 ) {
+ if (secondIndex != -1) {
key = requestPath.substring(secondIndex);
}
@@ -314,8 +315,7 @@ public class MapEntries implements EventHandler {
/**
* Handles the change to any of the node properties relevant for vanity URL
- * mappings. The
- * {@link #MapEntries(JcrResourceResolverFactoryImpl, BundleContext, ServiceTracker)}
+ * mappings. The {@link #MapEntries(ResourceResolverFactoryImpl, BundleContext, EventAdmin)}
* constructor makes sure the event listener is registered to only get
* appropriate events.
*/
@@ -340,7 +340,7 @@ public class MapEntries implements EventHandler {
boolean doInit = true;
if (SlingConstants.TOPIC_RESOURCE_REMOVED.equals(event.getTopic()) && !path.startsWith(this.mapRoot)) {
doInit = false;
- for (String target : this.vanityTargets) {
+ for (final String target : this.vanityTargets) {
if (target.startsWith(path)) {
doInit = true;
break;
@@ -360,46 +360,43 @@ public class MapEntries implements EventHandler {
* Send an OSGi event
*/
private void sendChangeEvent() {
- final EventAdmin ea = (EventAdmin) this.eventAdminTracker.getService();
- if (ea != null) {
+ if (this.eventAdmin != null) {
// we hard code the topic here and don't use
// SlingConstants.TOPIC_RESOURCE_RESOLVER_MAPPING_CHANGED
// to avoid requiring the latest API version for this bundle to work
final Event event = new Event("org/apache/sling/api/resource/ResourceResolverMapping/CHANGED",
- (Dictionary<?, ?>) null);
- ea.postEvent(event);
+ (Dictionary<?, ?>) null);
+ this.eventAdmin.postEvent(event);
}
}
- private void loadResolverMap(final ResourceResolver resolver,
- List<MapEntry> entries,
- Map<String, MapEntry> mapEntries) {
+ private void loadResolverMap(final ResourceResolver resolver, final List<MapEntry> entries, final Map<String, MapEntry> mapEntries) {
// the standard map configuration
- Resource res = resolver.getResource(mapRoot);
+ final Resource res = resolver.getResource(mapRoot);
if (res != null) {
gather(resolver, entries, mapEntries, res, "");
}
}
- private void gather(final ResourceResolver resolver,
- List<MapEntry> entries,
- Map<String, MapEntry> mapEntries, Resource parent, String parentPath) {
+ private void gather(final ResourceResolver resolver, final List<MapEntry> entries, final Map<String, MapEntry> mapEntries,
+ final Resource parent, final String parentPath) {
// scheme list
- Iterator<Resource> children = ResourceUtil.listChildren(parent);
+ final Iterator<Resource> children = parent.listChildren();
while (children.hasNext()) {
final Resource child = children.next();
final ValueMap vm = ResourceUtil.getValueMap(child);
- String name = vm.get(JcrResourceResolver.PROP_REG_EXP, String.class);
+ String name = vm.get(PROP_REG_EXP, String.class);
boolean trailingSlash = false;
if (name == null) {
- name = ResourceUtil.getName(child).concat("/");
+ name = child.getName().concat("/");
trailingSlash = true;
}
- String childPath = parentPath.concat(name);
+ final String childPath = parentPath.concat(name);
- // gather the children of this entry (only if child is not end hooked)
+ // gather the children of this entry (only if child is not end
+ // hooked)
if (!childPath.endsWith("$")) {
// add trailing slash to child path to append the child
@@ -412,19 +409,16 @@ public class MapEntries implements EventHandler {
}
// add resolution entries for this node
- final MapEntry childResolveEntry = MapEntry.createResolveEntry(childPath,
- child, trailingSlash);
+ final MapEntry childResolveEntry = MapEntry.createResolveEntry(childPath, child, trailingSlash);
if (childResolveEntry != null) {
entries.add(childResolveEntry);
}
// add map entries for this node
- List<MapEntry> childMapEntries = MapEntry.createMapEntry(childPath,
- child, trailingSlash);
+ final List<MapEntry> childMapEntries = MapEntry.createMapEntry(childPath, child, trailingSlash);
if (childMapEntries != null) {
- for (MapEntry mapEntry : childMapEntries) {
- addMapEntry(mapEntries, mapEntry.getPattern(),
- mapEntry.getRedirect()[0], mapEntry.getStatus());
+ for (final MapEntry mapEntry : childMapEntries) {
+ addMapEntry(mapEntries, mapEntry.getPattern(), mapEntry.getRedirect()[0], mapEntry.getStatus());
}
}
@@ -434,10 +428,9 @@ public class MapEntries implements EventHandler {
/**
* Add an entry to the resolve map.
*/
- private void addEntry(final Map<String, List<MapEntry>> entryMap,
- final String key, final MapEntry entry) {
+ private void addEntry(final Map<String, List<MapEntry>> entryMap, final String key, final MapEntry entry) {
List<MapEntry> entries = entryMap.get(key);
- if ( entries == null ) {
+ if (entries == null) {
entries = new ArrayList<MapEntry>();
entryMap.put(key, entries);
}
@@ -447,11 +440,10 @@ public class MapEntries implements EventHandler {
}
/**
- * Load vanity paths
- * Search for all nodes inheriting the sling:VanityPath mixin
+ * Load vanity paths Search for all nodes inheriting the sling:VanityPath
+ * mixin
*/
- private Collection<String> loadVanityPaths(final ResourceResolver resolver,
- final Map<String, List<MapEntry>> entryMap) {
+ private Collection<String> loadVanityPaths(final ResourceResolver resolver, final Map<String, List<MapEntry>> entryMap) {
// sling:VanityPath (uppercase V) is the mixin name
// sling:vanityPath (lowercase) is the property name
final Set<String> targetPaths = new HashSet<String>();
@@ -479,11 +471,13 @@ public class MapEntries implements EventHandler {
final String[] pVanityPaths = props.get("sling:vanityPath", new String[0]);
for (final String pVanityPath : pVanityPaths) {
final String[] result = this.getVanityPathDefinition(pVanityPath);
- if ( result != null ) {
+ if (result != null) {
final String url = result[0] + result[1];
- // redirect target is the node providing the sling:vanityPath
- // property (or its parent if the node is called jcr:content)
+ // redirect target is the node providing the
+ // sling:vanityPath
+ // property (or its parent if the node is called
+ // jcr:content)
final String redirect;
if (resource.getName().equals("jcr:content")) {
redirect = resource.getParent().getPath();
@@ -492,22 +486,21 @@ public class MapEntries implements EventHandler {
}
// whether the target is attained by a 302/FOUND or by an
- // internal redirect is defined by the sling:redirect property
- final int status = props.get("sling:redirect", false)
- ? props.get(JcrResourceResolver.PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS, HttpServletResponse.SC_FOUND)
- : -1;
-
- final String checkPath = result[1];
- // 1. entry with exact match
- this.addEntry(entryMap, checkPath, new MapEntry(url + "$", status, false, redirect
- + ".html"));
-
- // 2. entry with match supporting selectors and extension
- this.addEntry(entryMap, checkPath, new MapEntry(url + "(\\..*)", status, false,
- redirect + "$1"));
-
- // 3. keep the path to return
- targetPaths.add(redirect);
+ // internal redirect is defined by the sling:redirect
+ // property
+ final int status = props.get("sling:redirect", false) ? props.get(
+ PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS, HttpServletResponse.SC_FOUND)
+ : -1;
+
+ final String checkPath = result[1];
+ // 1. entry with exact match
+ this.addEntry(entryMap, checkPath, new MapEntry(url + "$", status, false, redirect + ".html"));
+
+ // 2. entry with match supporting selectors and extension
+ this.addEntry(entryMap, checkPath, new MapEntry(url + "(\\..*)", status, false, redirect + "$1"));
+
+ // 3. keep the path to return
+ targetPaths.add(redirect);
}
}
}
@@ -516,18 +509,17 @@ public class MapEntries implements EventHandler {
/**
* Create the vanity path definition. String array containing:
- * {protocol}/{host}[.port]
- * {absolute path}
+ * {protocol}/{host}[.port] {absolute path}
*/
private String[] getVanityPathDefinition(final String pVanityPath) {
String[] result = null;
- if ( pVanityPath != null ) {
+ if (pVanityPath != null) {
final String info = pVanityPath.trim();
- if ( info.length() > 0 ) {
+ if (info.length() > 0) {
String prefix = null;
String path = null;
// check for url
- if ( info.indexOf(":/") > - 1 ) {
+ if (info.indexOf(":/") > -1) {
try {
final URL u = new URL(info);
prefix = u.getProtocol() + '/' + u.getHost() + '.' + u.getPort();
@@ -537,7 +529,7 @@ public class MapEntries implements EventHandler {
}
} else {
prefix = "^" + ANY_SCHEME_HOST;
- if ( !info.startsWith("/") ) {
+ if (!info.startsWith("/")) {
path = "/" + info;
} else {
path = info;
@@ -545,22 +537,21 @@ public class MapEntries implements EventHandler {
}
// remove extension
- if ( prefix != null ) {
+ if (prefix != null) {
final int lastSlash = path.lastIndexOf('/');
final int firstDot = path.indexOf('.', lastSlash + 1);
- if ( firstDot != -1 ) {
+ if (firstDot != -1) {
path = path.substring(0, firstDot);
log.warn("Removing extension from vanity path {}", pVanityPath);
}
- result = new String[] {prefix, path};
+ result = new String[] { prefix, path };
}
}
}
return result;
}
- private void loadConfiguration(final JcrResourceResolverFactoryImpl factory,
- final List<MapEntry> entries) {
+ private void loadConfiguration(final ResourceResolverFactoryImpl factory, final List<MapEntry> entries) {
// virtual uris
final Map<?, ?> virtuals = factory.getVirtualURLMap();
if (virtuals != null) {
@@ -579,11 +570,11 @@ public class MapEntries implements EventHandler {
// URL Mappings
final Mapping[] mappings = factory.getMappings();
if (mappings != null) {
- Map<String, List<String>> map = new HashMap<String, List<String>>();
- for (Mapping mapping : mappings) {
+ final Map<String, List<String>> map = new HashMap<String, List<String>>();
+ for (final Mapping mapping : mappings) {
if (mapping.mapsInbound()) {
- String url = mapping.getTo();
- String alias = mapping.getFrom();
+ final String url = mapping.getTo();
+ final String alias = mapping.getFrom();
if (url.length() > 0) {
List<String> aliasList = map.get(url);
if (aliasList == null) {
@@ -596,22 +587,20 @@ public class MapEntries implements EventHandler {
}
for (final Entry<String, List<String>> entry : map.entrySet()) {
- entries.add(new MapEntry(ANY_SCHEME_HOST + entry.getKey(),
- -1, false, entry.getValue().toArray(new String[0])));
+ entries.add(new MapEntry(ANY_SCHEME_HOST + entry.getKey(), -1, false, entry.getValue().toArray(new String[0])));
}
}
}
- private void loadMapConfiguration(JcrResourceResolverFactoryImpl factory,
- Map<String, MapEntry> entries) {
+ private void loadMapConfiguration(final ResourceResolverFactoryImpl factory, final Map<String, MapEntry> entries) {
// URL Mappings
- Mapping[] mappings = factory.getMappings();
+ final Mapping[] mappings = factory.getMappings();
if (mappings != null) {
for (int i = mappings.length - 1; i >= 0; i--) {
- Mapping mapping = mappings[i];
+ final Mapping mapping = mappings[i];
if (mapping.mapsOutbound()) {
- String url = mapping.getTo();
- String alias = mapping.getFrom();
+ final String url = mapping.getTo();
+ final String alias = mapping.getFrom();
if (!url.equals(alias)) {
addMapEntry(entries, alias, url, -1);
}
@@ -620,33 +609,31 @@ public class MapEntries implements EventHandler {
}
// virtual uris
- Map<?, ?> virtuals = factory.getVirtualURLMap();
+ final Map<?, ?> virtuals = factory.getVirtualURLMap();
if (virtuals != null) {
- for (Entry<?, ?> virtualEntry : virtuals.entrySet()) {
- String extPath = (String) virtualEntry.getKey();
- String intPath = (String) virtualEntry.getValue();
+ for (final Entry<?, ?> virtualEntry : virtuals.entrySet()) {
+ final String extPath = (String) virtualEntry.getKey();
+ final String intPath = (String) virtualEntry.getValue();
if (!extPath.equals(intPath)) {
// this regular expression must match the whole URL !!
- String path = "^" + intPath + "$";
- String url = extPath;
+ final String path = "^" + intPath + "$";
+ final String url = extPath;
addMapEntry(entries, path, url, -1);
}
}
}
}
- private void addMapEntry(Map<String, MapEntry> entries, String path,
- String url, int status) {
+ private void addMapEntry(final Map<String, MapEntry> entries, final String path, final String url, final int status) {
MapEntry entry = entries.get(path);
if (entry == null) {
entry = new MapEntry(path, status, false, url);
} else {
- String[] redir = entry.getRedirect();
- String[] newRedir = new String[redir.length + 1];
+ final String[] redir = entry.getRedirect();
+ final String[] newRedir = new String[redir.length + 1];
System.arraycopy(redir, 0, newRedir, 0, redir.length);
newRedir[redir.length] = url;
- entry = new MapEntry(entry.getPattern(), entry.getStatus(),
- false, newRedir);
+ entry = new MapEntry(entry.getPattern(), entry.getStatus(), false, newRedir);
}
entries.put(path, entry);
}
@@ -658,19 +645,16 @@ public class MapEntries implements EventHandler {
* updating the internal structure
*/
private static String createFilter() {
- final String[] nodeProps = {
- "sling:vanityPath", "sling:vanityOrder", JcrResourceResolver.PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS,
- JcrResourceResolver.PROP_REDIRECT_EXTERNAL, JcrResourceResolver.PROP_REDIRECT_INTERNAL,
- JcrResourceResolver.PROP_REDIRECT_EXTERNAL_STATUS, JcrResourceResolver.PROP_REG_EXP
- };
- final String[] eventProps = {
- "resourceAddedAttributes", "resourceChangedAttributes", "resourceRemovedAttributes"
- };
- StringBuilder filter = new StringBuilder();
+ final String[] nodeProps = { "sling:vanityPath", "sling:vanityOrder",
+ PROP_REDIRECT_EXTERNAL_REDIRECT_STATUS, PROP_REDIRECT_EXTERNAL,
+ ResourceResolverImpl.PROP_REDIRECT_INTERNAL, PROP_REDIRECT_EXTERNAL_STATUS,
+ PROP_REG_EXP };
+ final String[] eventProps = { "resourceAddedAttributes", "resourceChangedAttributes", "resourceRemovedAttributes" };
+ final StringBuilder filter = new StringBuilder();
filter.append("(|");
- for (String eventProp : eventProps) {
+ for (final String eventProp : eventProps) {
filter.append("(|");
- for (String nodeProp : nodeProps) {
+ for (final String nodeProp : nodeProps) {
filter.append('(').append(eventProp).append('=').append(nodeProp).append(')');
}
filter.append(")");
@@ -689,7 +673,7 @@ public class MapEntries implements EventHandler {
private MapEntry next;
- private Iterator<MapEntry> globalListIterator;
+ private final Iterator<MapEntry> globalListIterator;
private MapEntry nextGlobal;
private Iterator<MapEntry> specialIterator;
@@ -702,7 +686,6 @@ public class MapEntries implements EventHandler {
this.seek();
}
-
/**
* @see java.util.Iterator#hasNext()
*/
@@ -714,7 +697,7 @@ public class MapEntries implements EventHandler {
* @see java.util.Iterator#next()
*/
public MapEntry next() {
- if ( this.next == null ) {
+ if (this.next == null) {
throw new NoSuchElementException();
}
final MapEntry result = this.next;
@@ -730,28 +713,28 @@ public class MapEntries implements EventHandler {
}
private void seek() {
- if ( this.nextGlobal == null && this.globalListIterator.hasNext() ) {
+ if (this.nextGlobal == null && this.globalListIterator.hasNext()) {
this.nextGlobal = this.globalListIterator.next();
}
- if ( this.nextSpecial == null ) {
- if ( specialIterator != null && !specialIterator.hasNext() ) {
+ if (this.nextSpecial == null) {
+ if (specialIterator != null && !specialIterator.hasNext()) {
specialIterator = null;
}
- while ( specialIterator == null && key != null ) {
+ while (specialIterator == null && key != null) {
// remove selectors and extension
final int lastSlashPos = key.lastIndexOf('/');
final int lastDotPos = key.indexOf('.', lastSlashPos);
- if ( lastDotPos != -1 ) {
+ if (lastDotPos != -1) {
key = key.substring(0, lastDotPos);
}
final List<MapEntry> special = this.resolveMapsMap.get(key);
- if ( special != null ) {
+ if (special != null) {
specialIterator = special.iterator();
}
// recurse to the parent
- if ( key.length() > 1 ) {
+ if (key.length() > 1) {
final int lastSlash = key.lastIndexOf("/");
- if ( lastSlash == 0 ) {
+ if (lastSlash == 0) {
key = null;
} else {
key = key.substring(0, lastSlash);
@@ -760,17 +743,17 @@ public class MapEntries implements EventHandler {
key = null;
}
}
- if ( this.specialIterator != null && this.specialIterator.hasNext() ) {
+ if (this.specialIterator != null && this.specialIterator.hasNext()) {
this.nextSpecial = this.specialIterator.next();
}
}
- if ( this.nextSpecial == null ) {
+ if (this.nextSpecial == null) {
this.next = this.nextGlobal;
this.nextGlobal = null;
- } else if ( this.nextGlobal == null ) {
+ } else if (this.nextGlobal == null) {
this.next = this.nextSpecial;
this.nextSpecial = null;
- } else if ( this.nextGlobal.getPattern().length() >= this.nextSpecial.getPattern().length() ) {
+ } else if (this.nextGlobal.getPattern().length() >= this.nextSpecial.getPattern().length()) {
this.next = this.nextGlobal;
this.nextGlobal = null;
} else {
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntry.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntry.java
index be94165..c45767b 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntry.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntry.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.mapping;
import java.net.URI;
import java.net.URISyntaxException;
@@ -28,14 +28,14 @@ import java.util.regex.Pattern;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.jcr.resource.internal.JcrResourceResolver;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
import org.slf4j.LoggerFactory;
/**
* The <code>MapEntry</code> class represents a mapping entry in the mapping
* configuration tree at <code>/etc/map</code>.
* <p>
- *
+ *
* @see "http://cwiki.apache.org/SLING/flexible-resource-resolution.html"
*/
public class MapEntry implements Comparable<MapEntry> {
@@ -72,22 +72,26 @@ public class MapEntry implements Comparable<MapEntry> {
/**
* Returns a string used for matching map entries against the given request
* or URI parts.
- *
- * @param scheme The URI scheme
- * @param host The host name
- * @param port The port number. If this is negative, the default value used
+ *
+ * @param scheme
+ * The URI scheme
+ * @param host
+ * The host name
+ * @param port
+ * The port number. If this is negative, the default value used
* is 80 unless the scheme is "https" in which case the default
* value is 443.
- * @param path The (absolute) path
+ * @param path
+ * The (absolute) path
* @return The request path string {scheme}://{host}:{port}{path}.
*/
- public static String getURI(String scheme, String host, int port,
- String path) {
+ public static String getURI(final String scheme, final String host, final int port,
+ final String path) {
- StringBuilder sb = new StringBuilder();
+ final StringBuilder sb = new StringBuilder();
sb.append(scheme).append("://").append(host);
if (port > 0 && !(port == 80 && "http".equals(scheme))
- && !(port == 443 && "https".equals(scheme))) {
+ && !(port == 443 && "https".equals(scheme))) {
sb.append(':').append(port);
}
sb.append(path);
@@ -95,9 +99,9 @@ public class MapEntry implements Comparable<MapEntry> {
return sb.toString();
}
- public static String fixUriPath(String uriPath) {
+ public static String fixUriPath(final String uriPath) {
for (int i = 0; i < URL_WITH_PORT_MATCH.length; i++) {
- Matcher m = URL_WITH_PORT_MATCH[i].matcher(uriPath);
+ final Matcher m = URL_WITH_PORT_MATCH[i].matcher(uriPath);
if (m.find()) {
return m.replaceAll(URL_WITH_PORT_REPLACEMENT[i]);
}
@@ -106,14 +110,14 @@ public class MapEntry implements Comparable<MapEntry> {
return uriPath;
}
- public static URI toURI(String uriPath) {
+ public static URI toURI(final String uriPath) {
for (int i = 0; i < PATH_TO_URL_MATCH.length; i++) {
- Matcher m = PATH_TO_URL_MATCH[i].matcher(uriPath);
+ final Matcher m = PATH_TO_URL_MATCH[i].matcher(uriPath);
if (m.find()) {
- String newUriPath = m.replaceAll(PATH_TO_URL_REPLACEMENT[i]);
+ final String newUriPath = m.replaceAll(PATH_TO_URL_REPLACEMENT[i]);
try {
return new URI(newUriPath);
- } catch (URISyntaxException use) {
+ } catch (final URISyntaxException use) {
// ignore, just don't return the uri as such
}
}
@@ -122,24 +126,26 @@ public class MapEntry implements Comparable<MapEntry> {
return null;
}
- public static MapEntry createResolveEntry(String url, Resource resource,
- boolean trailingSlash) {
- ValueMap props = resource.adaptTo(ValueMap.class);
+ public static MapEntry createResolveEntry(String url, final Resource resource,
+ final boolean trailingSlash) {
+ final ValueMap props = resource.adaptTo(ValueMap.class);
if (props != null) {
// ensure the url contains a port number (if possible)
url = fixUriPath(url);
- String redirect = props.get(
- JcrResourceResolver.PROP_REDIRECT_EXTERNAL, String.class);
+ final String redirect = props.get(
+ MapEntries.PROP_REDIRECT_EXTERNAL, String.class);
if (redirect != null) {
- int status = props.get(
- JcrResourceResolver.PROP_REDIRECT_EXTERNAL_STATUS, 302);
+ final int status = props
+ .get(MapEntries.PROP_REDIRECT_EXTERNAL_STATUS,
+ 302);
return new MapEntry(url, status, trailingSlash, redirect);
}
- String[] internalRedirect = props.get(
- JcrResourceResolver.PROP_REDIRECT_INTERNAL, String[].class);
+ final String[] internalRedirect = props
+ .get(ResourceResolverImpl.PROP_REDIRECT_INTERNAL,
+ String[].class);
if (internalRedirect != null) {
return new MapEntry(url, -1, trailingSlash, internalRedirect);
}
@@ -148,25 +154,27 @@ public class MapEntry implements Comparable<MapEntry> {
return null;
}
- public static List<MapEntry> createMapEntry(String url, Resource resource,
- boolean trailingSlash) {
- ValueMap props = resource.adaptTo(ValueMap.class);
+ public static List<MapEntry> createMapEntry(String url, final Resource resource,
+ final boolean trailingSlash) {
+ final ValueMap props = resource.adaptTo(ValueMap.class);
if (props != null) {
- String redirect = props.get(
- JcrResourceResolver.PROP_REDIRECT_EXTERNAL, String.class);
+ final String redirect = props.get(
+ MapEntries.PROP_REDIRECT_EXTERNAL, String.class);
if (redirect != null) {
// ignoring external redirects for mapping
- LoggerFactory.getLogger(MapEntry.class).info(
- "createMapEntry: Configuration has external redirect to {}; not creating mapping for configuration in {}",
- redirect, resource.getPath());
+ LoggerFactory
+ .getLogger(MapEntry.class)
+ .info("createMapEntry: Configuration has external redirect to {}; not creating mapping for configuration in {}",
+ redirect, resource.getPath());
return null;
}
// ignore potential regular expression url
if (isRegExp(url)) {
- LoggerFactory.getLogger(MapEntry.class).info(
- "createMapEntry: URL {} contains a regular expression; not creating mapping for configuration in {}",
- url, resource.getPath());
+ LoggerFactory
+ .getLogger(MapEntry.class)
+ .info("createMapEntry: URL {} contains a regular expression; not creating mapping for configuration in {}",
+ url, resource.getPath());
return null;
}
@@ -175,7 +183,7 @@ public class MapEntry implements Comparable<MapEntry> {
String endHook = "";
if (url.endsWith("$")) {
endHook = "$";
- url = url.substring(0, url.length()-1);
+ url = url.substring(0, url.length() - 1);
}
// check whether the url is for ANY_SCHEME_HOST
@@ -183,25 +191,26 @@ public class MapEntry implements Comparable<MapEntry> {
url = url.substring(MapEntries.ANY_SCHEME_HOST.length());
}
- String[] internalRedirect = props.get(
- JcrResourceResolver.PROP_REDIRECT_INTERNAL, String[].class);
+ final String[] internalRedirect = props
+ .get(ResourceResolverImpl.PROP_REDIRECT_INTERNAL,
+ String[].class);
if (internalRedirect != null) {
int status = -1;
- URI extPathPrefix = toURI(url);
+ final URI extPathPrefix = toURI(url);
if (extPathPrefix != null) {
url = getURI(extPathPrefix.getScheme(),
- extPathPrefix.getHost(), extPathPrefix.getPort(),
- extPathPrefix.getPath());
+ extPathPrefix.getHost(), extPathPrefix.getPort(),
+ extPathPrefix.getPath());
status = 302;
}
- List<MapEntry> prepEntries = new ArrayList<MapEntry>(
- internalRedirect.length);
- for (String redir : internalRedirect) {
+ final List<MapEntry> prepEntries = new ArrayList<MapEntry>(
+ internalRedirect.length);
+ for (final String redir : internalRedirect) {
if (!redir.contains("$")) {
prepEntries.add(new MapEntry(redir.concat(endHook),
- status, trailingSlash, url));
+ status, trailingSlash, url));
}
}
@@ -214,8 +223,8 @@ public class MapEntry implements Comparable<MapEntry> {
return null;
}
- public MapEntry(String url, int status, boolean trailingSlash,
- String... redirect) {
+ public MapEntry(String url, final int status, final boolean trailingSlash,
+ final String... redirect) {
// ensure trailing slashes on redirects if the url
// ends with a trailing slash
@@ -237,11 +246,11 @@ public class MapEntry implements Comparable<MapEntry> {
}
// Returns the replacement or null if the value does not match
- public String[] replace(String value) {
- Matcher m = urlPattern.matcher(value);
+ public String[] replace(final String value) {
+ final Matcher m = urlPattern.matcher(value);
if (m.find()) {
- String[] redirects = getRedirect();
- String[] results = new String[redirects.length];
+ final String[] redirects = getRedirect();
+ final String[] results = new String[redirects.length];
for (int i = 0; i < redirects.length; i++) {
results[i] = m.replaceFirst(redirects[i]);
}
@@ -269,13 +278,13 @@ public class MapEntry implements Comparable<MapEntry> {
// ---------- Comparable
- public int compareTo(MapEntry m) {
+ public int compareTo(final MapEntry m) {
if (this == m) {
return 0;
}
- int tlen = urlPattern.toString().length();
- int mlen = m.urlPattern.toString().length();
+ final int tlen = urlPattern.toString().length();
+ final int mlen = m.urlPattern.toString().length();
if (tlen < mlen) {
return 1;
} else if (tlen > mlen) {
@@ -291,7 +300,7 @@ public class MapEntry implements Comparable<MapEntry> {
@Override
public String toString() {
- StringBuilder buf = new StringBuilder();
+ final StringBuilder buf = new StringBuilder();
buf.append("MapEntry: match:").append(urlPattern);
buf.append(", replacement:");
@@ -309,17 +318,18 @@ public class MapEntry implements Comparable<MapEntry> {
return buf.toString();
}
- //---------- helper
+ // ---------- helper
/**
* Returns <code>true</code> if the string contains unescaped regular
* expression special characters '+', '*', '?', '|', '(', '), '[', and ']'
+ *
* @param string
* @return
*/
private static boolean isRegExp(final String string) {
- for (int i=0; i < string.length(); i++) {
- char c = string.charAt(i);
+ for (int i = 0; i < string.length(); i++) {
+ final char c = string.charAt(i);
if (c == '\\') {
i++; // just skip
} else if ("+*?|()[]".indexOf(c) >= 0) {
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/Mapping.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/Mapping.java
index b6b9087..4d4f0d9 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/Mapping.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/Mapping.java
@@ -16,15 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.mapping;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- * The <code>Mapping</code> class conveys the mapping configuration used by
- * the
- * {@link org.apache.sling.jcr.resource.internal.JcrResourceResolverFactoryImpl}.
+ * The <code>Mapping</code> class conveys the mapping configuration used by the
+ * {@link org.apache.sling.resourceresolver.impl.ResourceResolverFactoryImpl}.
*/
public class Mapping {
@@ -66,10 +65,11 @@ public class Mapping {
// Regular expression to split mapping configuration strings into three
// groups:
- // 1 - external path prefix
- // 2 - direction (Outbound (>), Bidirectional (:), Inbound (>))
- // 3 - internap path prefix
- private static final Pattern CONFIG_SPLITTER = Pattern.compile("(.+)([:<>])(.+)");
+ // 1 - external path prefix
+ // 2 - direction (Outbound (>), Bidirectional (:), Inbound (>))
+ // 3 - internap path prefix
+ private static final Pattern CONFIG_SPLITTER = Pattern
+ .compile("(.+)([:<>])(.+)");
/** the 'from' (inside, repository) mapping */
private final String from;
@@ -96,51 +96,52 @@ public class Mapping {
this.fromLength = this.from.length();
this.toLength = this.to.length();
- this.direction = ">".equals(parts[1])
- ? Mapping.INBOUND
- : ("<".equals(parts[1]) ? Mapping.OUTBOUND : Mapping.BOTH);
+ this.direction = ">".equals(parts[1]) ? Mapping.INBOUND : ("<"
+ .equals(parts[1]) ? Mapping.OUTBOUND : Mapping.BOTH);
}
@Override
public String toString() {
- return "Mapping (from=" + from + ", to=" + to + ", direction=" + direction
- + ", lengths=" + fromLength + "/" + toLength;
+ return "Mapping (from=" + from + ", to=" + to + ", direction="
+ + direction + ", lengths=" + fromLength + "/" + toLength;
}
/**
- * Replaces the prefix <em>to</em> by the new prefix <em>from</em>, if
- * and only if <code>uriPath</code> starts with the <em>to</em> prefix.
- * If <code>uriPath</code> does not start with the <em>to</em> prefix,
- * or if this mapping is not defined as a 'inward' mapping,
- * <code>null</code> is returned.
- *
- * @param uriPath The URI path for which to replace the <em>to</em> prefix
- * by the <em>from</em> prefix.
+ * Replaces the prefix <em>to</em> by the new prefix <em>from</em>, if and
+ * only if <code>uriPath</code> starts with the <em>to</em> prefix. If
+ * <code>uriPath</code> does not start with the <em>to</em> prefix, or if
+ * this mapping is not defined as a 'inward' mapping, <code>null</code> is
+ * returned.
+ *
+ * @param uriPath
+ * The URI path for which to replace the <em>to</em> prefix by
+ * the <em>from</em> prefix.
* @return The string after replacement or <code>null</code> if the
- * <code>uriPath</code> does not start with the <em>to</em>
- * prefix, or {@link #mapsInbound()} returns <code>false</code>.
+ * <code>uriPath</code> does not start with the <em>to</em> prefix,
+ * or {@link #mapsInbound()} returns <code>false</code>.
*/
public String mapUri(String uriPath) {
return (this.mapsInbound() && uriPath.startsWith(this.to)) ? this.from
- + uriPath.substring(this.toLength) : null;
+ + uriPath.substring(this.toLength) : null;
}
/**
- * Replaces the prefix <em>from</em> by the new prefix <em>to</em>, if
- * and only if <code>handle</code> starts with the <em>from</em> prefix.
- * If <code>uriPath</code> does not start with the <em>from</em> prefix,
- * or if this mapping is not defined as a 'outward' mapping,
- * <code>null</code> is returned.
- *
- * @param handle The URI path for which to replace the <em>from</em>
- * prefix by the <em>to</em> prefix.
+ * Replaces the prefix <em>from</em> by the new prefix <em>to</em>, if and
+ * only if <code>handle</code> starts with the <em>from</em> prefix. If
+ * <code>uriPath</code> does not start with the <em>from</em> prefix, or if
+ * this mapping is not defined as a 'outward' mapping, <code>null</code> is
+ * returned.
+ *
+ * @param handle
+ * The URI path for which to replace the <em>from</em> prefix by
+ * the <em>to</em> prefix.
* @return The string after replacement or <code>null</code> if the
- * <code>handle</code> does not start with the <em>from</em>
- * prefix, or {@link #mapsOutbound()} returns <code>false</code>.
+ * <code>handle</code> does not start with the <em>from</em> prefix,
+ * or {@link #mapsOutbound()} returns <code>false</code>.
*/
public String mapHandle(String handle) {
return (this.mapsOutbound() && handle.startsWith(this.from)) ? this.to
- + handle.substring(this.fromLength) : null;
+ + handle.substring(this.fromLength) : null;
}
// TODO: temporary
@@ -155,9 +156,9 @@ public class Mapping {
/**
* Checks, if this mapping is defined for inbound mapping.
- *
- * @return <code>true</code> if this mapping is defined for inbound
- * mapping; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if this mapping is defined for inbound mapping;
+ * <code>false</code> otherwise
*/
public boolean mapsInbound() {
return (this.direction & Mapping.INBOUND) > 0;
@@ -165,7 +166,7 @@ public class Mapping {
/**
* Checks, if this mapping is defined for outbound mapping.
- *
+ *
* @return <code>true</code> if this mapping is defined for outbound
* mapping; <code>false</code> otherwise
*/
@@ -190,15 +191,15 @@ public class Mapping {
Matcher mapMatch = CONFIG_SPLITTER.matcher(map);
if (mapMatch.matches()) {
return new String[] { mapMatch.group(1), mapMatch.group(2),
- mapMatch.group(3) };
+ mapMatch.group(3) };
}
// backwards compatibility using "-" instead of ":"
int dash = map.indexOf('-');
if (dash > 0) {
return new String[] { map.substring(0, dash),
- map.substring(dash, dash + 1),
- map.substring(dash + 1, map.length()) };
+ map.substring(dash, dash + 1),
+ map.substring(dash + 1, map.length()) };
}
return new String[] { map, "-", map };
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java b/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java
index 1700b77..b5eb3d7 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java
@@ -15,93 +15,143 @@
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.tree;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
-
-import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Map;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.osgi.framework.Constants;
/**
- *
+ * The provider handler is the common base class for the
+ * {@link ResourceProviderHandler} and the
+ * {@link ResourceProviderFactoryHandler}.
*/
-public class WrappedResourceProvider implements ResourceProvider {
+public abstract class ProviderHandler implements Comparable<ProviderHandler> {
+
+ /** Service properties. */
+ private final Map<String, Object> properties;
+
+ /** Unique service id */
+ private final Long serviceId;
- private ResourceProvider resourceProvider;
- private Comparable<?> serviceReference;
+ /** Configured roots. */
+ private final String[] roots;
/**
- *
+ * Create a new handler
*/
- public WrappedResourceProvider(ResourceProvider resourceProvider, Comparable<?> serviceReference) {
- this.resourceProvider = resourceProvider;
- this.serviceReference = serviceReference;
+ public ProviderHandler(final Map<String, Object> properties) {
+ this.properties = properties;
+ this.serviceId = (Long) properties.get(Constants.SERVICE_ID);
+ // calculate roots
+ final List<String> configuredRoots = new ArrayList<String>();
+ final String[] paths = PropertiesUtil.toStringArray(properties.get(ResourceProvider.ROOTS));
+ if ( paths != null) {
+ for(final String r : paths) {
+ if (r != null) {
+ String path = r.trim();
+ // cut off trailing slash
+ if (path.endsWith("/") && path.length() > 1) {
+ path = path.substring(0, path.length() - 1);
+ }
+ if ( path.length() > 0 && !configuredRoots.contains(path)) {
+ configuredRoots.add(path);
+ }
+ }
+ }
+ }
+ if ( configuredRoots.size() == 0 ) {
+ this.roots = null;
+ } else {
+ Collections.sort(configuredRoots);
+ this.roots = configuredRoots.toArray(new String[configuredRoots.size()]);
+ }
}
/**
- * {@inheritDoc}
- * @see org.apache.sling.api.resource.ResourceProvider#getResource(org.apache.sling.api.resource.ResourceResolver, java.lang.String)
+ * Return the service properties.
*/
- public Resource getResource(ResourceResolver arg0, String arg1) {
- return resourceProvider.getResource(arg0, arg1);
+ public Map<String, Object> getProperties() {
+ return this.properties;
}
/**
- * {@inheritDoc}
- * @see org.apache.sling.api.resource.ResourceProvider#getResource(org.apache.sling.api.resource.ResourceResolver, javax.servlet.http.HttpServletRequest, java.lang.String)
+ * Return the service id.
*/
- public Resource getResource(ResourceResolver arg0, HttpServletRequest arg1, String arg2) {
- return resourceProvider.getResource(arg0, arg1, arg2);
+ public Long getServiceId() {
+ return this.serviceId;
}
/**
- * {@inheritDoc}
- * @see org.apache.sling.api.resource.ResourceProvider#listChildren(org.apache.sling.api.resource.Resource)
+ * Return a sorted array of roots for this provider. If no roots are configured,
+ * this will return <code>null</code>
+ * @return The array of roots or <code>null</code>
*/
- public Iterator<Resource> listChildren(Resource arg0) {
- return resourceProvider.listChildren(arg0);
+ public String[] getRoots() {
+ return this.roots;
}
/**
- *
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
*/
- public Comparable<?> getComparable() {
- return serviceReference;
+ public int compareTo(final ProviderHandler other) {
+ if (this.serviceId.equals(other.serviceId)) {
+ return 0; // same service
+ }
+
+ Object rankObj = this.getProperties().get(Constants.SERVICE_RANKING);
+ Object otherRankObj = other.getProperties().get(Constants.SERVICE_RANKING);
+
+ // If no rank, then spec says it defaults to zero.
+ rankObj = (rankObj == null) ? new Integer(0) : rankObj;
+ otherRankObj = (otherRankObj == null) ? new Integer(0) : otherRankObj;
+
+ // If rank is not Integer, then spec says it defaults to zero.
+ Integer rank = (rankObj instanceof Integer)
+ ? (Integer) rankObj : new Integer(0);
+ Integer otherRank = (otherRankObj instanceof Integer)
+ ? (Integer) otherRankObj : new Integer(0);
+
+ // Sort by rank in ascending order.
+ if (rank.compareTo(otherRank) < 0) {
+ return -1; // lower rank
+ } else if (rank.compareTo(otherRank) > 0) {
+ return 1; // higher rank
+ }
+
+ // If ranks are equal, then sort by service id in descending order.
+ return (this.serviceId.compareTo(other.serviceId) < 0) ? 1 : -1;
}
/**
- * {@inheritDoc}
- * @see java.lang.Object#hashCode()
+ * @see ResourceProvider#getResource(ResourceResolver, String)
*/
- @Override
- public int hashCode() {
- return resourceProvider.hashCode();
- }
+ public abstract Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path);
/**
- * {@inheritDoc}
- * @see java.lang.Object#equals(java.lang.Object)
+ * @see ResourceProvider#listChildren(Resource)
*/
- @Override
- public boolean equals(Object obj) {
- if ( obj instanceof WrappedResourceProvider ) {
- return resourceProvider.equals(((WrappedResourceProvider) obj).resourceProvider);
- } else if ( obj instanceof ResourceProvider) {
- return resourceProvider.equals(obj);
- }
- return super.equals(obj);
- }
+ public abstract Iterator<Resource> listChildren(final ResourceResolverContext ctx, final Resource parent);
/**
- * {@inheritDoc}
- *
- * @see java.lang.Object#toString()
+ * Return a name of the resource provider/factory.
*/
- @Override
- public String toString() {
- return resourceProvider.toString();
+ public String getName() {
+ final StringBuilder snBuilder = new StringBuilder(64);
+ snBuilder.append('{');
+ snBuilder.append(this.toString());
+ snBuilder.append('/');
+ snBuilder.append(this.serviceId.toString());
+ snBuilder.append('}');
+ return snBuilder.toString();
}
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java b/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
index c5c4e76..f1322cd 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
@@ -16,13 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -32,6 +31,7 @@ import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,16 +39,9 @@ import org.slf4j.LoggerFactory;
* The <code>ResourceProviderEntry</code> class represents a node in the tree of
* resource providers spanned by the root paths of the provider resources.
* <p>
- * This class is comparable to itself to help keep the child entries list sorted
- * by their prefix.
+ * This class is comparable to itself to help keep the child entries list sorted by their prefix.
*/
-public class ResourceProviderEntry implements
- Comparable<ResourceProviderEntry> {
-
- /**
- *
- */
- private static final long serialVersionUID = 7420631325909144862L;
+public class ResourceProviderEntry implements Comparable<ResourceProviderEntry> {
private static Logger LOGGER = LoggerFactory.getLogger(ResourceProviderEntry.class);
@@ -64,7 +57,7 @@ public class ResourceProviderEntry implements
// the resource provider kept in this entry supporting resources at and
// below the path of this entry.
- private WrappedResourceProvider[] providers = new WrappedResourceProvider[0];
+ private ProviderHandler[] providers = new ProviderHandler[0];
private long ttime = 0L;
@@ -74,7 +67,7 @@ public class ResourceProviderEntry implements
private long nreal = 0L;
- private FastTreeMap storageMap = new FastTreeMap();
+ private final FastTreeMap storageMap = new FastTreeMap();
private Collection<ResourceProviderEntry> storageMapValues = new ArrayList<ResourceProviderEntry>();
@@ -88,7 +81,7 @@ public class ResourceProviderEntry implements
* @param providerList
* The resource provider to encapsulate by this entry.
*/
- public ResourceProviderEntry(String path, ResourceProvider[] providerList) {
+ public ResourceProviderEntry(final String path, final ProviderHandler[] providerList) {
if (path.endsWith("/")) {
this.path = path.substring(0, path.length() - 1);
this.prefix = path;
@@ -96,15 +89,11 @@ public class ResourceProviderEntry implements
this.path = path;
this.prefix = path + "/";
}
- if ( providerList != null ) {
- providers = new WrappedResourceProvider[providerList.length];
- for ( int i = 0; i < providerList.length; i++ ) {
- if ( providerList[i] instanceof WrappedResourceProvider ) {
- providers[i] = (WrappedResourceProvider) providerList[i];
- } else {
- providers[i] = new WrappedResourceProvider(providerList[i], null);
+ if (providerList != null) {
+ providers = new ProviderHandler[providerList.length];
+ for (int i = 0; i < providerList.length; i++) {
+ providers[i] = providerList[i];
}
- }
}
// this will consume slightly more memory but ensures read is fast.
@@ -112,14 +101,14 @@ public class ResourceProviderEntry implements
}
- String getPath() {
+ public String getPath() {
return path;
}
/**
- * Returns the resource provider contained in this entry
+ * Returns the resource providers contained in this entry
*/
- public ResourceProvider[] getResourceProviders() {
+ public ProviderHandler[] getResourceProviders() {
return providers;
}
@@ -135,8 +124,8 @@ public class ResourceProviderEntry implements
* @throws org.apache.sling.api.SlingException
* if an error occurrs trying to access an existing resource.
*/
- public Resource getResource(ResourceResolver resourceResolver, String path) {
- return getInternalResource(resourceResolver, path);
+ public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path) {
+ return getInternalResource(ctx, resourceResolver, path);
}
/**
@@ -146,38 +135,36 @@ public class ResourceProviderEntry implements
* subtree below this entry. Otherwise <code>false</code> is
* returned.
*/
- public boolean addResourceProvider(String prefix, ResourceProvider provider, Comparable<?> comparable) {
- synchronized (this) {
- String[] elements = split(prefix, '/');
- List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
- entryPath.add(this); // add this the start so if the list is empty we have a position to add to
- populateProviderPath(entryPath, elements);
- for (int i = entryPath.size() - 1; i < elements.length; i++) {
- String stubPrefix = elements[i];
- ResourceProviderEntry rpe2 = new ResourceProviderEntry(
- stubPrefix, new ResourceProvider[0]);
- entryPath.get(i).put(elements[i], rpe2);
- entryPath.add(rpe2);
- }
- return entryPath.get(elements.length).addInternalProvider(new WrappedResourceProvider(provider, comparable));
-
+ public synchronized boolean addResourceProvider(final String prefix, final ProviderHandler provider) {
+ final String[] elements = split(prefix, '/');
+ final List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
+ entryPath.add(this); // add this the start so if the list is empty
+ // we have a position to add to
+ populateProviderPath(entryPath, elements);
+ for (int i = entryPath.size() - 1; i < elements.length; i++) {
+ final String stubPrefix = elements[i];
+ final ResourceProviderEntry rpe2 = new ResourceProviderEntry(stubPrefix, new ProviderHandler[0]);
+ entryPath.get(i).put(stubPrefix, rpe2);
+ entryPath.add(rpe2);
}
+ return entryPath.get(elements.length).addInternalProvider(provider);
}
-
- //------------------ Map methods, here so that we can delegate 2 maps together
+ // ------------------ Map methods, here so that we can delegate 2 maps
+ // together
@SuppressWarnings("unchecked")
- public void put(String key, ResourceProviderEntry value) {
- storageMap.put(key,value);
- // get a thread safe copy, the ArrayList constructor does a toArray which is thread safe.
+ public void put(final String key, final ResourceProviderEntry value) {
+ storageMap.put(key, value);
+ // get a thread safe copy, the ArrayList constructor does a toArray
+ // which is thread safe.
storageMapValues = new ArrayList<ResourceProviderEntry>(storageMap.values());
}
- public boolean containsKey(String key) {
+ public boolean containsKey(final String key) {
return storageMap.containsKey(key);
}
- public ResourceProviderEntry get(String key) {
+ public ResourceProviderEntry get(final String key) {
return (ResourceProviderEntry) storageMap.get(key);
}
@@ -185,23 +172,20 @@ public class ResourceProviderEntry implements
return storageMapValues;
}
- public boolean removeResourceProvider(String prefix,
- ResourceProvider resourceProvider, Comparable<?> comparable) {
- synchronized (this) {
- String[] elements = split(prefix, '/');
- List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
- populateProviderPath(entryPath, elements);
- if (entryPath.size() > 0 && entryPath.size() == elements.length) {
- // the last element is a perfect match;
- return entryPath.get(entryPath.size()-1).removeInternalProvider(new WrappedResourceProvider(resourceProvider, comparable));
- }
- return false;
+ public synchronized boolean removeResourceProvider(final String prefix, final ProviderHandler resourceProvider) {
+ final String[] elements = split(prefix, '/');
+ final List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
+ populateProviderPath(entryPath, elements);
+ if (entryPath.size() > 0 && entryPath.size() == elements.length) {
+ // the last element is a perfect match;
+ return entryPath.get(entryPath.size() - 1).removeInternalProvider(resourceProvider);
}
+ return false;
}
// ---------- Comparable<ResourceProviderEntry> interface ------------------
- public int compareTo(ResourceProviderEntry o) {
+ public int compareTo(final ResourceProviderEntry o) {
return prefix.compareTo(o.prefix);
}
@@ -210,69 +194,46 @@ public class ResourceProviderEntry implements
/**
* Adds a list of providers to this entry.
*
- * @param provider
+ * No sync required as this is called by a sync method!
*/
- private boolean addInternalProvider(WrappedResourceProvider provider) {
- synchronized (providers) {
- int before = providers.length;
- Set<WrappedResourceProvider> set = new HashSet<WrappedResourceProvider>();
- if (providers != null) {
- set.addAll(Arrays.asList(providers));
- }
- LOGGER.debug("Adding provider {} at {} ",provider,path);
- set.add(provider);
- providers = conditionalSort(set);
- return providers.length > before;
+ private boolean addInternalProvider(final ProviderHandler provider) {
+ final int before = providers.length;
+ final Set<ProviderHandler> set = new HashSet<ProviderHandler>();
+ if (providers != null) {
+ set.addAll(Arrays.asList(providers));
}
-
+ LOGGER.debug("Adding provider {} at {} ", provider, path);
+ set.add(provider);
+ providers = conditionalSort(set);
+ return providers.length > before;
}
/**
- * @param provider
- * @return
+ * Remove a provider from the list of entries.
+ *
+ * No sync required as this is called by a sync method!
*/
- private boolean removeInternalProvider(WrappedResourceProvider provider) {
- synchronized (providers) {
- int before = providers.length;
- Set<WrappedResourceProvider> set = new HashSet<WrappedResourceProvider>();
- if (providers != null) {
- set.addAll(Arrays.asList(providers));
- }
- set.remove(provider);
- providers = conditionalSort(set);
- return providers.length < before;
+ private boolean removeInternalProvider(final ProviderHandler provider) {
+ final int before = providers.length;
+ final Set<ProviderHandler> set = new HashSet<ProviderHandler>();
+ if (providers != null) {
+ set.addAll(Arrays.asList(providers));
}
+ set.remove(provider);
+ providers = conditionalSort(set);
+ return providers.length < before;
}
/**
- * @param set
- * @return
+ * Return a sorted array of handlers.
*/
- private WrappedResourceProvider[] conditionalSort(Set<WrappedResourceProvider> set) {
-
- List<WrappedResourceProvider> providerList = new ArrayList<WrappedResourceProvider>(
- set);
+ private ProviderHandler[] conditionalSort(final Set<ProviderHandler> set) {
- Collections.sort(providerList, new Comparator<WrappedResourceProvider>() {
+ final List<ProviderHandler> providerList = new ArrayList<ProviderHandler>(set);
- @SuppressWarnings("unchecked")
- public int compare(WrappedResourceProvider o1, WrappedResourceProvider o2) {
- Comparable c1 = o1.getComparable();
- Comparable c2 = o2.getComparable();
- if ( c1 == null && c2 == null ) {
- return 0;
- }
- if ( c1 == null ) {
- return -1;
- }
- if ( c2 == null ) {
- return 1;
- }
- return c1.compareTo(c2);
- }
- });
+ Collections.sort(providerList);
- return set.toArray(new WrappedResourceProvider[set.size()]);
+ return providerList.toArray(new ProviderHandler[providerList.size()]);
}
/**
@@ -282,11 +243,10 @@ public class ResourceProviderEntry implements
* @param fullPath
* the full path
*/
- private void populateProviderPath(
- List<ResourceProviderEntry> providerEntryPath, String[] elements) {
+ private void populateProviderPath(final List<ResourceProviderEntry> providerEntryPath, final String[] elements) {
ResourceProviderEntry base = this;
if (elements != null) {
- for (String element : elements) {
+ for (final String element : elements) {
if (element != null) {
if (base.containsKey(element)) {
base = base.get(element);
@@ -299,7 +259,6 @@ public class ResourceProviderEntry implements
}
}
-
/**
* Resolve a resource from a path into a Resource
*
@@ -309,41 +268,36 @@ public class ResourceProviderEntry implements
* the Full path
* @return null if no resource was found, a resource if one was found.
*/
- private Resource getInternalResource(ResourceResolver resourceResolver,
- String fullPath) {
- long start = System.currentTimeMillis();
+ private Resource getInternalResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String fullPath) {
+ final long start = System.currentTimeMillis();
try {
- if (fullPath == null || fullPath.length() == 0
- || fullPath.charAt(0) != '/') {
+ if (fullPath == null || fullPath.length() == 0 || fullPath.charAt(0) != '/') {
nmiss++;
- LOGGER.debug("Not absolute {} :{}",fullPath,(System.currentTimeMillis() - start));
+ LOGGER.debug("Not absolute {} :{}", fullPath, (System.currentTimeMillis() - start));
return null; // fullpath must be absolute
}
- String[] elements = split(fullPath, '/');
+ final String[] elements = split(fullPath, '/');
- List<ResourceProviderEntry> list = new ArrayList<ResourceProviderEntry>();
+ final List<ResourceProviderEntry> list = new ArrayList<ResourceProviderEntry>();
populateProviderPath(list, elements);
// the path is in reverse order end first
- for(int i = list.size()-1; i >= 0; i--) {
- ResourceProvider[] rps = list.get(i).getResourceProviders();
- for (ResourceProvider rp : rps) {
+ for (int i = list.size() - 1; i >= 0; i--) {
+ final ProviderHandler[] rps = list.get(i).getResourceProviders();
+ for (final ProviderHandler rp : rps) {
- Resource resource = rp.getResource(resourceResolver,
- fullPath);
+ final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
if (resource != null) {
nreal++;
- LOGGER.debug("Resolved Full {} using {} from {} ",new Object[]{
- fullPath, rp, Arrays.toString(rps)});
+ LOGGER.debug("Resolved Full {} using {} from {} ", new Object[] { fullPath, rp, Arrays.toString(rps) });
return resource;
}
}
}
// resolve against this one
- final Resource resource = getResourceFromProviders(
- resourceResolver, fullPath);
+ final Resource resource = getResourceFromProviders(ctx, resourceResolver, fullPath);
if (resource != null) {
return resource;
}
@@ -352,34 +306,29 @@ public class ResourceProviderEntry implements
// resource Provider: libs/sling/servlet/default/GET.servlet
// list will match libs, sling, servlet, default
// and there will be no resource provider at the end
- if (list.size() > 0 && list.size() == elements.length ) {
- if ( list.get(list.size()-1).getResourceProviders().length == 0 ) {
+ if (list.size() > 0 && list.size() == elements.length) {
+ if (list.get(list.size() - 1).getResourceProviders().length == 0) {
nsynthetic++;
LOGGER.debug("Resolved Synthetic {}", fullPath);
- return new SyntheticResource(resourceResolver,
- fullPath,
- ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+ return new SyntheticResource(resourceResolver, fullPath, ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
}
}
-
-
LOGGER.debug("Resource null {} ", fullPath);
nmiss++;
return null;
- } catch (Exception ex) {
- LOGGER.debug("Failed! ",ex);
+ } catch (final Exception ex) {
+ LOGGER.debug("Failed! ", ex);
return null;
} finally {
ttime += System.currentTimeMillis() - start;
}
}
- Resource getResourceFromProviders(final ResourceResolver resourceResolver,
- final String fullPath) {
- ResourceProvider[] rps = getResourceProviders();
- for (ResourceProvider rp : rps) {
- Resource resource = rp.getResource(resourceResolver, fullPath);
+ public Resource getResourceFromProviders(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String fullPath) {
+ final ProviderHandler[] rps = getResourceProviders();
+ for (final ProviderHandler rp : rps) {
+ final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
if (resource != null) {
nreal++;
LOGGER.debug("Resolved Base {} using {} ", fullPath, rp);
@@ -394,12 +343,12 @@ public class ResourceProviderEntry implements
* @param sep
* @return an array of the strings between the separator
*/
- static String[] split(String st, char sep) {
+ public static String[] split(final String st, final char sep) {
if (st == null) {
return new String[0];
}
- char[] pn = st.toCharArray();
+ final char[] pn = st.toCharArray();
if (pn.length == 0) {
return new String[0];
}
@@ -418,7 +367,7 @@ public class ResourceProviderEntry implements
n++;
}
}
- String[] e = new String[n];
+ final String[] e = new String[n];
int s = start;
int j = 0;
for (int i = start; i < end; i++) {
@@ -434,18 +383,17 @@ public class ResourceProviderEntry implements
}
public String getResolutionStats() {
- long tot = nreal + nsynthetic + nmiss;
+ final long tot = nreal + nsynthetic + nmiss;
if (tot == 0) {
return null;
}
- float n = tot;
- float t = ttime;
- float persec = 1000 * n / t;
- float avgtime = t / n;
-
- String stat = "Resolved: Real(" + nreal + ") Synthetic(" + nsynthetic
- + ") Missing(" + nmiss + ") Total(" + tot + ") at " + persec
- + " ops/sec avg " + avgtime + " ms";
+ final float n = tot;
+ final float t = ttime;
+ final float persec = 1000 * n / t;
+ final float avgtime = t / n;
+
+ final String stat = "Resolved: Real(" + nreal + ") Synthetic(" + nsynthetic + ") Missing(" + nmiss + ") Total(" + tot + ") at "
+ + persec + " ops/sec avg " + avgtime + " ms";
ttime = nmiss = nsynthetic = nreal = 0L;
return stat;
}
@@ -458,7 +406,8 @@ public class ResourceProviderEntry implements
@Override
public String toString() {
return this.path;
- //"{path:\"" + this.path + "\", providers:"+Arrays.toString(getResourceProviders())+", map:" + storageMap.toString() + "}";
+ // "{path:\"" + this.path +
+ // "\", providers:"+Arrays.toString(getResourceProviders())+", map:" +
+ // storageMap.toString() + "}";
}
-
}
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java b/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java
index aeb550d..4acf626 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java
@@ -16,124 +16,403 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.tree;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Dictionary;
+import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.AttributableResourceProvider;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.QueriableResourceProvider;
+import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
-import org.apache.sling.commons.osgi.OsgiUtil;
-import org.osgi.framework.Constants;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.helper.SortedProviderList;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
-import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * This is the root resource provider entry which keeps track
- * of the resource providers.
+ * This is the root resource provider entry which keeps track of the resource
+ * providers.
*/
public class RootResourceProviderEntry extends ResourceProviderEntry {
- /** default logger */
+ /** Default logger */
private final Logger logger = LoggerFactory.getLogger(getClass());
+ /** Event admin. */
+ private EventAdmin eventAdmin;
+
+ /** Array of required factories. */
+ private ResourceProviderFactoryHandler[] requiredFactories = new ResourceProviderFactoryHandler[0];
+
+ /** All adaptable resource providers. */
+ private final SortedProviderList<Adaptable> adaptableProviders = new SortedProviderList<Adaptable>(Adaptable.class);
+
+ /** All queriable resource providers. */
+ private final SortedProviderList<QueriableResourceProvider> queriableProviders = new SortedProviderList<QueriableResourceProvider>(QueriableResourceProvider.class);
+
+ /** All attributable resource providers. */
+ private final SortedProviderList<AttributableResourceProvider> attributableProviders = new SortedProviderList<AttributableResourceProvider>(AttributableResourceProvider.class);
+
public RootResourceProviderEntry() {
super("/", null);
}
- public void bindResourceProvider(final ResourceProvider provider,
- final Map<String, Object> props,
- final ServiceTracker eventAdminTracker) {
+ /**
+ * Set or unset the event admin.
+ */
+ public void setEventAdmin(final EventAdmin ea) {
+ this.eventAdmin = ea;
+ }
- final String serviceName = getServiceName(provider, props);
+ /**
+ * Login into all required factories
+ * @throws LoginException If login fails.
+ */
+ public void loginToRequiredFactories(final ResourceResolverContext ctx) throws LoginException {
+ try {
+ final ResourceProviderFactoryHandler[] factories = this.requiredFactories;
+ for (final ResourceProviderFactoryHandler wrapper : factories) {
+ wrapper.login(ctx);
+ }
+ } catch (final LoginException le) {
+ // login failed, so logout if already logged in providers
+ ctx.close();
+ throw le;
+ }
+ }
- logger.debug("bindResourceProvider: Binding {}", serviceName);
+ /**
+ * Invoke all resource providers and find an adaption
+ * @see Adaptable
+ */
+ public <AdapterType> AdapterType adaptTo(final ResourceResolverContext ctx, final Class<AdapterType> type) {
+ final Iterator<Adaptable> i = this.adaptableProviders.getProviders(ctx);
+ AdapterType result = null;
+ while ( result == null && i.hasNext() ) {
+ final Adaptable adap = i.next();
+ result = adap.adaptTo(type);
+ }
+ return result;
+ }
+
+ /**
+ * Invoke all queriable resource providers.
+ * @see QueriableResourceProvider#findResources(ResourceResolver, String, String)
+ */
+ public Iterator<Resource> findResources(final ResourceResolverContext ctx,
+ final ResourceResolver resolver, final String query, final String language) {
+ final Iterator<QueriableResourceProvider> i = this.queriableProviders.getProviders(ctx);
+ return new Iterator<Resource>() {
+
+ private Resource nextObject = this.seek();
- String[] roots = OsgiUtil.toStringArray(props.get(ResourceProvider.ROOTS));
- if (roots != null && roots.length > 0) {
- final EventAdmin localEA = (EventAdmin) ( eventAdminTracker != null ? eventAdminTracker.getService() : null);
+ private Iterator<Resource> nextResourceIter;
- for (String root : roots) {
- // cut off trailing slash
- if (root.endsWith("/") && root.length() > 1) {
- root = root.substring(0, root.length() - 1);
+ private Resource seek() {
+ Resource result = null;
+ if ( nextResourceIter == null || !nextResourceIter.hasNext() ) {
+ nextResourceIter = null;
+ while ( i.hasNext() && nextResourceIter == null ) {
+ final QueriableResourceProvider adap = i.next();
+ nextResourceIter = adap.findResources(resolver, query, language);
+ }
}
+ if ( nextResourceIter != null ) {
+ while ( nextResourceIter.hasNext() && result == null ) {
+ result = nextResourceIter.next();
+ }
+ if ( result == null ) {
+ result = seek();
+ }
+ }
+ return result;
+ }
- // synchronized insertion of new resource providers into
- // the tree to not inadvertently loose an entry
- synchronized (this) {
+ /**
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return this.nextObject != null;
+ }
- this.addResourceProvider(root,
- provider, OsgiUtil.getComparableForServiceRanking(props));
+ /**
+ * @see java.util.Iterator#next()
+ */
+ public Resource next() {
+ if ( this.nextObject == null ) {
+ throw new NoSuchElementException();
}
- logger.debug("bindResourceProvider: {}={} ({})",
- new Object[] { root, provider, serviceName });
- if ( localEA != null ) {
- final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
- eventProps.put(SlingConstants.PROPERTY_PATH, root);
- localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED,
- eventProps));
+ final Resource result = this.nextObject;
+ this.nextObject = this.seek();
+ return result;
+ }
+
+ /**
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Invoke all queriable resource providers.
+ * @see QueriableResourceProvider#queryResources(String, String)
+ */
+ public Iterator<Map<String, Object>> queryResources(final ResourceResolverContext ctx, final String query, final String language) {
+ final Iterator<QueriableResourceProvider> i = this.queriableProviders.getProviders(ctx);
+ return new Iterator<Map<String, Object>>() {
+
+ private Map<String, Object> nextObject = this.seek();
+
+ private Iterator<Map<String, Object>> nextResourceIter;
+
+ private Map<String, Object> seek() {
+ Map<String, Object> result = null;
+ if ( nextResourceIter == null || !nextResourceIter.hasNext() ) {
+ nextResourceIter = null;
+ while ( i.hasNext() && nextResourceIter == null ) {
+ final QueriableResourceProvider adap = i.next();
+ nextResourceIter = adap.queryResources(query, language);
+ }
+ }
+ if ( nextResourceIter != null ) {
+ while ( nextResourceIter.hasNext() && result == null ) {
+ result = nextResourceIter.next();
+ }
+ if ( result == null ) {
+ result = seek();
+ }
}
+ return result;
+ }
+
+ /**
+ * @see java.util.Iterator#hasNext()
+ */
+ public boolean hasNext() {
+ return this.nextObject != null;
}
+
+ /**
+ * @see java.util.Iterator#next()
+ */
+ public Map<String, Object> next() {
+ if ( this.nextObject == null ) {
+ throw new NoSuchElementException();
+ }
+ final Map<String, Object> result = this.nextObject;
+ this.nextObject = this.seek();
+ return result;
+ }
+
+ /**
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ private static final String FORBIDDEN_ATTRIBUTE = ResourceResolverFactory.PASSWORD;
+
+ /**
+ * Invoke all attributes providers and combine the result
+ * @see AttributableResourceProvider#getAttributeNames()
+ */
+ public Iterator<String> getAttributeNames(final ResourceResolverContext ctx) {
+ final Set<String> names = new HashSet<String>();
+ if ( ctx.getAuthenticationInfo() != null ) {
+ names.addAll(ctx.getAuthenticationInfo().keySet());
}
+ final Iterator<AttributableResourceProvider> i = this.attributableProviders.getProviders(ctx);
+ while ( i.hasNext() ) {
+ final AttributableResourceProvider adap = i.next();
+ final Collection<String> newNames = adap.getAttributeNames();
+ if ( newNames != null ) {
+ names.addAll(newNames);
+ }
+ }
+ names.remove(FORBIDDEN_ATTRIBUTE);
+
+ return names.iterator();
+ }
- logger.debug("bindResourceProvider: Bound {}", serviceName);
+ /**
+ * Return the result from the first matching attributes provider
+ * @see AttributableResourceProvider#getAttribute(String)
+ */
+ public Object getAttribute(final ResourceResolverContext ctx, final String name) {
+ Object result = null;
+ if (!FORBIDDEN_ATTRIBUTE.equals(name) ) {
+ if (ctx.getAuthenticationInfo() != null) {
+ result = ctx.getAuthenticationInfo().get(name);
+ }
+ if ( result == null ) {
+ final Iterator<AttributableResourceProvider> i = this.attributableProviders.getProviders(ctx);
+ while ( result == null && i.hasNext() ) {
+ final AttributableResourceProvider adap = i.next();
+ result = adap.getAttribute(name);
+ }
+ }
+ }
+ return result;
}
- public void unbindResourceProvider(final ResourceProvider provider,
- final Map<String, Object> props,
- final ServiceTracker eventAdminTracker) {
+ /**
+ * Bind a resource provider.
+ */
+ public void bindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+ final ResourceProviderHandler handler = new ResourceProviderHandler(provider, props);
- final String serviceName = getServiceName(provider, props);
+ this.bindHandler(handler);
+ this.adaptableProviders.add(handler);
+ this.queriableProviders.add(handler);
+ this.attributableProviders.add(handler);
+ }
- logger.debug("unbindResourceProvider: Unbinding {}", serviceName);
+ /**
+ * Unbind a resource provider.
+ */
+ public void unbindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+ final ResourceProviderHandler handler = new ResourceProviderHandler(provider, props);
- String[] roots = OsgiUtil.toStringArray(props.get(ResourceProvider.ROOTS));
- if (roots != null && roots.length > 0) {
+ this.unbindHandler(handler);
+ this.adaptableProviders.remove(handler);
+ this.queriableProviders.remove(handler);
+ this.attributableProviders.remove(handler);
+ }
- final EventAdmin localEA = (EventAdmin) ( eventAdminTracker != null ? eventAdminTracker.getService() : null);
+ /**
+ * Bind a resource provider factory.
+ */
+ public void bindResourceProviderFactory(final ResourceProviderFactory factory, final Map<String, Object> props) {
+ final ResourceProviderFactoryHandler handler = new ResourceProviderFactoryHandler(factory, props);
- for (String root : roots) {
- // cut off trailing slash
- if (root.endsWith("/") && root.length() > 1) {
- root = root.substring(0, root.length() - 1);
- }
+ this.bindHandler(handler);
+ this.adaptableProviders.add(handler);
+ this.queriableProviders.add(handler);
+ this.attributableProviders.add(handler);
- // synchronized insertion of new resource providers into
- // the tree to not inadvertently loose an entry
- synchronized (this) {
- // TODO: Do not remove this path, if another resource
- // owns it. This may be the case if adding the provider
- // yielded an ResourceProviderEntryException
- this.removeResourceProvider(root, provider, OsgiUtil.getComparableForServiceRanking(props));
+ final boolean required = PropertiesUtil.toBoolean(props.get(ResourceProviderFactory.PROPERTY_REQUIRED), false);
+ if (required) {
+ synchronized (this) {
+ final List<ResourceProviderFactoryHandler> factories = new LinkedList<ResourceProviderFactoryHandler>();
+ factories.addAll(Arrays.asList(this.requiredFactories));
+ factories.add(handler);
+ this.requiredFactories = factories.toArray(new ResourceProviderFactoryHandler[factories.size()]);
+ }
+ }
+ }
+
+ /**
+ * Unbind a resource provider factory
+ */
+ public void unbindResourceProviderFactory(final ResourceProviderFactory factory, final Map<String, Object> props) {
+ final ResourceProviderFactoryHandler handler = new ResourceProviderFactoryHandler(factory, props);
+
+ this.unbindHandler(handler);
+ this.adaptableProviders.remove(handler);
+ this.queriableProviders.remove(handler);
+ this.attributableProviders.remove(handler);
+
+ final boolean required = PropertiesUtil.toBoolean(props.get(ResourceProviderFactory.PROPERTY_REQUIRED), false);
+ if (required) {
+ synchronized (this) {
+ final List<ResourceProviderFactoryHandler> factories = new LinkedList<ResourceProviderFactoryHandler>();
+ factories.addAll(Arrays.asList(this.requiredFactories));
+ factories.remove(handler);
+ this.requiredFactories = factories.toArray(new ResourceProviderFactoryHandler[factories.size()]);
+ }
+ }
+ }
+
+ /**
+ * Bind a resource provider wrapper
+ */
+ private void bindHandler(final ProviderHandler provider) {
+ // this is just used for debug logging
+ final String debugServiceName = getDebugServiceName(provider);
+
+ logger.debug("bindResourceProvider: Binding {}", debugServiceName);
+
+ final String[] roots = provider.getRoots();
+ boolean foundRoot = false;
+ if (roots != null) {
+ final EventAdmin localEA = this.eventAdmin;
+ for (final String root : roots) {
+ foundRoot = true;
+
+ this.addResourceProvider(root, provider);
+
+ logger.debug("bindResourceProvider: {}={} ({})", new Object[] { root, provider, debugServiceName });
+ if (localEA != null) {
+ final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
+ eventProps.put(SlingConstants.PROPERTY_PATH, root);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED, eventProps));
}
- logger.debug("unbindResourceProvider: root={} ({})", root,
- serviceName);
- if ( localEA != null ) {
+ }
+ }
+ if ( !foundRoot ) {
+ logger.info("Ignoring ResourceProvider(Factory) {} : no configured roots.", provider.getName());
+ }
+ logger.debug("bindResourceProvider: Bound {}", debugServiceName);
+ }
+
+ /**
+ * Unbind a resource provider wrapper
+ */
+ private void unbindHandler(final ProviderHandler provider) {
+ // this is just used for debug logging
+ final String debugServiceName = getDebugServiceName(provider);
+
+ logger.debug("unbindResourceProvider: Unbinding {}", debugServiceName);
+
+ final String[] roots = provider.getRoots();
+ if (roots != null) {
+
+ final EventAdmin localEA = this.eventAdmin;
+
+ for (final String root : roots) {
+
+ this.removeResourceProvider(root, provider);
+
+ logger.debug("unbindResourceProvider: root={} ({})", root, debugServiceName);
+ if (localEA != null) {
final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
eventProps.put(SlingConstants.PROPERTY_PATH, root);
- localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED,
- eventProps));
+ localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED, eventProps));
}
}
}
- logger.debug("unbindResourceProvider: Unbound {}", serviceName);
+ logger.debug("unbindResourceProvider: Unbound {}", debugServiceName);
}
- private String getServiceName(final ResourceProvider provider, final Map<String, Object> props) {
+ private String getDebugServiceName(final ProviderHandler provider) {
if (logger.isDebugEnabled()) {
- StringBuilder snBuilder = new StringBuilder(64);
- snBuilder.append('{');
- snBuilder.append(provider.toString());
- snBuilder.append('/');
- snBuilder.append(props.get(Constants.SERVICE_ID));
- snBuilder.append('}');
- return snBuilder.toString();
+ return provider.getName();
}
return null;
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..68a4969
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the SCR plugin
+
+#
+# Localizations for JcrResourceResolverFactoryImpl configuration
+resource.resolver.name = Apache Sling JCR Resource Resolver
+resource.resolver.description = Configures the JCR Resource Resolver for request \
+ URL and resource path rewriting.
+
+resource.resolver.map.location.name = Mapping Location
+resource.resolver.map.location.description = The path to the root of the \
+ configuration to setup and configure the ResourceResolver mapping. The \
+ default value is /etc/map.
+
+resource.resolver.allowDirect.name = Allow Direct Mapping
+resource.resolver.allowDirect.description = Whether to add a direct URL \
+ mapping to the front of the mapping list.
+
+resource.resolver.virtual.name = Virtual URLs
+resource.resolver.virtual.description = List of virtual URLs and there \
+ mappings to real URLs. Format is <externalURL>:<internalURL>. Mappings are \
+ applied on the complete request URL only.
+
+resource.resolver.mapping.name = URL Mappings
+resource.resolver.mapping.description = List of mappings to apply to URLs. \
+ Incoming mappings are applied to request URLs to map to Content paths, \
+ outgoing mappings are applied to map Content paths to URLs used on subsequent \
+ requests. Form ist <externalURLPrefix><op><internalURLPrefix> where <op> is \
+ ">" for incoming mappings, "<" for outgoing mappings and ":" for mappings \
+ applied in both directions. Mappings are applied in configuration order by \
+ comparing and replacing URL prefixes. Note: The use of "-" as the <op> value \
+ indicating a mapping in both directions is deprecated.
+
+resource.resolver.searchpath.name = Resource Search Path
+resource.resolver.searchpath.description = The list of absolute path prefixes \
+ applied to find resources whose path is just specified with a relative path. \
+ The default value is [ "/apps", "/libs" ]. If an empty path is specified a \
+ single entry path of [ "/" ] is assumed.
+
+resource.resolver.manglenamespaces.name = Namespace Mangling
+resource.resolver.manglenamespaces.description = Defines whether namespace \
+ prefixes of resource names inside the path (e.g. "jcr:" in "/home/path/jcr:content") \
+ are mangled or not. Mangling means that any namespace prefix contained in the \
+ path is replaced as per the generic substitution pattern "/([^:]+):/_$1_/" \
+ when calling the "map" method of the resource resolver. Likewise the \
+ "resolve" methods will unmangle such namespace prefixes according to the \
+ substituation pattern "/_([^_]+)_/$1:/". This feature is provided since \
+ there may be systems out there in the wild which cannot cope with URLs \
+ containing colons, even though they are perfectly valid characters in the \
+ path part of URI references with a scheme. The default value of this property \
+ if no configuration is provided is "true".
+
+resource.resolver.multiworkspace.name=Enable Multi Workspaces
+resource.resolver.multiworkspace.description=If this is enabled, multiple workspaces are supported \
+ This includes registering observation listeners for all workspaces and allows to \
+ resolve resources from other workspaces than the default one.
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
new file mode 100644
index 0000000..985b889
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
@@ -0,0 +1,547 @@
+/*
+ * 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.resourceresolver.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.jcr.Session;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.sling.api.resource.NonExistingResource;
+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.resourceresolver.impl.helper.ResourceResolverContext;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ResourceResolverImplTest {
+
+ private ResourceResolver resResolver;
+
+ private ResourceResolverFactoryImpl resFac;
+
+ @Before public void setup() {
+ resFac = new ResourceResolverFactoryImpl();
+ resResolver = new ResourceResolverImpl(resFac, new ResourceResolverContext(false, null));
+ }
+
+ @Test public void testClose() throws Exception {
+ final ResourceResolver rr = new ResourceResolverImpl(resFac, new ResourceResolverContext(false, null));
+ assertTrue(rr.isLive());
+ rr.close();
+ assertFalse(rr.isLive());
+ // close is always allowed to be called
+ rr.close();
+ assertFalse(rr.isLive());
+ // now check all public method - they should all throw!
+ try {
+ rr.adaptTo(Session.class);
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.clone(null);
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.findResources("a", "b");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getAttribute("a");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getAttributeNames();
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getResource(null);
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getResource(null, "/a");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getSearchPath();
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.getUserID();
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.listChildren(null);
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.map("/somepath");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.map(null, "/somepath");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.queryResources("a", "b");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.resolve((HttpServletRequest)null);
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.resolve("/path");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ try {
+ rr.resolve(null, "/path");
+ fail();
+ } catch (final IllegalStateException ise) {
+ // expected
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test public void testBasicAPIAssumptions() throws Exception {
+
+ // null resource is accessing /, which exists of course
+ final Resource res00 = resResolver.resolve((String) null);
+ assertNotNull(res00);
+ assertTrue("Resource must be NonExistingResource",
+ res00 instanceof NonExistingResource);
+ assertEquals("Null path is expected to return root", "/",
+ res00.getPath());
+
+ // relative paths are treated as if absolute
+ final String path01 = "relPath/relPath";
+ final Resource res01 = resResolver.resolve(path01);
+ assertNotNull(res01);
+ assertEquals("Expecting absolute path for relative path", "/" + path01,
+ res01.getPath());
+ assertTrue("Resource must be NonExistingResource",
+ res01 instanceof NonExistingResource);
+
+ final String no_resource_path = "/no_resource/at/this/location";
+ final Resource res02 = resResolver.resolve(no_resource_path);
+ assertNotNull(res02);
+ assertEquals("Expecting absolute path for relative path",
+ no_resource_path, res02.getPath());
+ assertTrue("Resource must be NonExistingResource",
+ res01 instanceof NonExistingResource);
+
+ try {
+ resResolver.resolve((HttpServletRequest) null);
+ fail("Expected NullPointerException trying to resolve null request");
+ } catch (NullPointerException npe) {
+ // expected
+ }
+
+ final Resource res0 = resResolver.resolve(null, no_resource_path);
+ assertNotNull("Expecting resource if resolution fails", res0);
+ assertTrue("Resource must be NonExistingResource",
+ res0 instanceof NonExistingResource);
+ assertEquals("Path must be the original path", no_resource_path,
+ res0.getPath());
+
+ final HttpServletRequest req1 = new ResourceResolverTestRequest(
+ no_resource_path);
+ final Resource res1 = resResolver.resolve(req1);
+ assertNotNull("Expecting resource if resolution fails", res1);
+ assertTrue("Resource must be NonExistingResource",
+ res1 instanceof NonExistingResource);
+ assertEquals("Path must be the original path", no_resource_path,
+ res1.getPath());
+
+ final HttpServletRequest req2 = new ResourceResolverTestRequest(null);
+ final Resource res2 = resResolver.resolve(req2);
+ assertNotNull("Expecting resource if resolution fails", res2);
+ assertTrue("Resource must be NonExistingResource",
+ res2 instanceof NonExistingResource);
+ assertEquals("Path must be the the root path", "/", res2.getPath());
+ }
+
+ @Test public void test_clone_based_on_anonymous() throws Exception {
+ final ResourceResolver anon0 = resFac.getResourceResolver((Map<String, Object>) null);
+ // no session
+ final Session anon0Session = anon0.adaptTo(Session.class);
+ assertNull("Session should not be available", anon0Session);
+ // no user information, so user id is null
+ assertEquals(null, anon0.getUserID());
+
+ // same user and workspace
+ final ResourceResolver anon1 = anon0.clone(null);
+ final Session anon1Session = anon1.adaptTo(Session.class);
+ assertEquals(anon0.getUserID(), anon1.getUserID());
+ assertNull("Session should not be available", anon1Session);
+ anon1.close();
+
+ // same workspace but admin user
+ final Map<String, Object> admin0Cred = new HashMap<String, Object>();
+ admin0Cred.put(ResourceResolverFactory.USER, "admin");
+ admin0Cred.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+ final ResourceResolver admin0 = anon0.clone(admin0Cred);
+ assertEquals("admin", admin0.getUserID());
+ admin0.close();
+
+ anon0.close();
+ }
+
+ @Test public void test_clone_based_on_admin() throws Exception {
+ final ResourceResolver admin0 = resFac.getAdministrativeResourceResolver((Map<String, Object>) null);
+ // no user information, so user id is null
+ assertEquals(null, admin0.getUserID());
+
+ // same user and workspace
+ final ResourceResolver admin1 = admin0.clone(null);
+ assertEquals(admin0.getUserID(), admin1.getUserID());
+ admin1.close();
+
+ // same workspace but anonymous user
+ final Map<String, Object> anon0Cred = new HashMap<String, Object>();
+ anon0Cred.put(ResourceResolverFactory.USER, "anonymous");
+ final ResourceResolver anon0 = admin0.clone(anon0Cred);
+ assertEquals("anonymous", anon0.getUserID());
+ anon0.close();
+
+ admin0.close();
+ }
+
+ @Test public void test_attributes_from_authInfo() throws Exception {
+ final Map<String, Object> authInfo = new HashMap<String, Object>();
+ authInfo.put(ResourceResolverFactory.USER, "admin");
+ authInfo.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+ authInfo.put("testAttributeString", "AStringValue");
+ authInfo.put("testAttributeNumber", 999);
+ final ResourceResolver rr = resFac.getResourceResolver(authInfo);
+
+ assertEquals("AStringValue", rr.getAttribute("testAttributeString"));
+ assertEquals(999, rr.getAttribute("testAttributeNumber"));
+ assertEquals("admin", rr.getAttribute(ResourceResolverFactory.USER));
+ assertNull(rr.getAttribute(ResourceResolverFactory.PASSWORD));
+
+ final HashSet<String> validNames = new HashSet<String>();
+ validNames.add(ResourceResolverFactory.USER);
+ validNames.add("testAttributeString");
+ validNames.add("testAttributeNumber");
+ final Iterator<String> names = rr.getAttributeNames();
+ assertTrue(validNames.remove(names.next()));
+ assertTrue(validNames.remove(names.next()));
+ assertTrue(validNames.remove(names.next()));
+ assertFalse("Expect no more names", names.hasNext());
+ assertTrue("Expect validNames set to be empty now",
+ validNames.isEmpty());
+
+ rr.close();
+ }
+
+ private static final class ResourceResolverTestRequest implements
+ HttpServletRequest {
+
+ private final String pathInfo;
+
+ private final String method;
+
+ private final String scheme;
+
+ private final String host;
+
+ private final int port;
+
+ private final Map<String, Object> attrs = new HashMap<String, Object>();
+
+ private String contextPath;
+
+ ResourceResolverTestRequest(String pathInfo) {
+ this(null, null, -1, pathInfo, null);
+ }
+
+ ResourceResolverTestRequest(String scheme, String host, int port,
+ String pathInfo, String httpMethod) {
+ this.scheme = (scheme == null) ? "http" : scheme;
+ this.host = (host == null) ? "localhost" : host;
+ this.port = port;
+ this.pathInfo = pathInfo;
+ this.method = httpMethod;
+ }
+
+ public String getPathInfo() {
+ return pathInfo;
+ }
+
+ public Object getAttribute(String name) {
+ return attrs.get(name);
+ }
+
+ public Enumeration<?> getAttributeNames() {
+ return null;
+ }
+
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ public int getContentLength() {
+ return 0;
+ }
+
+ public String getContentType() {
+ return null;
+ }
+
+ public ServletInputStream getInputStream() {
+ return null;
+ }
+
+ public String getLocalAddr() {
+ return null;
+ }
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public int getLocalPort() {
+ return 0;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public Enumeration<?> getLocales() {
+ return null;
+ }
+
+ public String getParameter(String name) {
+ return null;
+ }
+
+ public Map<?, ?> getParameterMap() {
+ return null;
+ }
+
+ public Enumeration<?> getParameterNames() {
+ return null;
+ }
+
+ public String[] getParameterValues(String name) {
+ return null;
+ }
+
+ public String getProtocol() {
+ return null;
+ }
+
+ public BufferedReader getReader() {
+ return null;
+ }
+
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ public String getRemoteHost() {
+ return null;
+ }
+
+ public int getRemotePort() {
+ return 0;
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ public String getScheme() {
+ return scheme;
+ }
+
+ public String getServerName() {
+ return host;
+ }
+
+ public int getServerPort() {
+ return port;
+ }
+
+ public boolean isSecure() {
+ return false;
+ }
+
+ public String getContextPath() {
+ return contextPath;
+ }
+
+ public void removeAttribute(String name) {
+ }
+
+ public void setAttribute(String name, Object o) {
+ attrs.put(name, o);
+ }
+
+ public void setCharacterEncoding(String env) {
+ }
+
+ public String getAuthType() {
+ return null;
+ }
+
+ public Cookie[] getCookies() {
+ return null;
+ }
+
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ public String getHeader(String name) {
+ return null;
+ }
+
+ public Enumeration<?> getHeaderNames() {
+ return null;
+ }
+
+ public Enumeration<?> getHeaders(String name) {
+ return null;
+ }
+
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public String getPathTranslated() {
+ return null;
+ }
+
+ public String getQueryString() {
+ return null;
+ }
+
+ public String getRemoteUser() {
+ return null;
+ }
+
+ public String getRequestURI() {
+ return null;
+ }
+
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ public String getServletPath() {
+ return null;
+ }
+
+ public HttpSession getSession() {
+ return null;
+ }
+
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java
new file mode 100644
index 0000000..26eba27
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.resourceresolver.impl.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistableValueMap;
+import org.apache.sling.api.resource.ValueMap;
+import org.junit.Test;
+
+public class RedirectResourceTest {
+
+ @Test public void testRedirectResource() {
+
+ final String path = "/redir/path";
+ final String target = "/redir/target";
+ final int status = 999;
+ final RedirectResource res = new RedirectResource(null, path, target,
+ status);
+
+ assertEquals(path, res.getPath());
+ assertEquals(RedirectResource.RT_SLING_REDIRECT, res.getResourceType());
+
+ final Map<?, ?> map = res.adaptTo(Map.class);
+ assertNotNull("Expected Map adapter", map);
+ assertEquals(target, map.get(RedirectResource.PROP_SLING_TARGET));
+ assertEquals(status, ((Integer) map.get(RedirectResource.PROP_SLING_STATUS)).intValue());
+
+ final ValueMap valueMap = res.adaptTo(ValueMap.class);
+ assertNotNull("Expected ValueMap adapter", valueMap);
+ assertEquals(target, valueMap.get(RedirectResource.PROP_SLING_TARGET));
+ assertEquals(status, ((Integer) valueMap.get(RedirectResource.PROP_SLING_STATUS)).intValue());
+ assertEquals(status, valueMap.get(RedirectResource.PROP_SLING_STATUS, Integer.class).intValue());
+
+ final PersistableValueMap persistableValueMap = res.adaptTo(PersistableValueMap.class);
+ assertNull("Unexpected PersistableValueMap adapter",
+ persistableValueMap);
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java
new file mode 100644
index 0000000..d70ffd7
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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.resourceresolver.impl.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.junit.Test;
+
+public class ResourcePathIteratorTest {
+
+ @Test public void testNull() {
+ ResourcePathIterator rpi = new ResourcePathIterator(null);
+ assertFinished(rpi);
+ }
+
+ @Test public void testEmpty() {
+ ResourcePathIterator rpi = new ResourcePathIterator("");
+ assertFinished(rpi);
+ }
+
+ @Test public void testRoot() {
+ ResourcePathIterator rpi = new ResourcePathIterator("/");
+ assertNext("/", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testSlashed() {
+ ResourcePathIterator rpi = new ResourcePathIterator("/root/child");
+ assertNext("/root/child", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testSlashedTrailingSlash1() {
+ ResourcePathIterator rpi = new ResourcePathIterator("/root/child/");
+ assertNext("/root/child", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testSlashedTrailingSlash2() {
+ ResourcePathIterator rpi = new ResourcePathIterator("/root/child//");
+ assertNext("/root/child", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testDotted() {
+ ResourcePathIterator rpi = new ResourcePathIterator("/root.child");
+ assertNext("/root.child", rpi);
+ assertNext("/root", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testMixed() {
+ ResourcePathIterator rpi = new ResourcePathIterator(
+ "/root/child.print.a4.html/with/suffix");
+ assertNext("/root/child.print.a4.html/with/suffix", rpi);
+ assertNext("/root/child.print.a4", rpi);
+ assertNext("/root/child.print", rpi);
+ assertNext("/root/child", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testNoSeparators() {
+ final Iterator<String> rpi = new ResourcePathIterator(
+ "MickeyMouseWasHere");
+ assertNext("MickeyMouseWasHere", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testGetA() {
+ final Iterator<String> rpi = new ResourcePathIterator(
+ "/some/stuff/more.a4.html");
+ assertNext("/some/stuff/more.a4.html", rpi);
+ assertNext("/some/stuff/more.a4", rpi);
+ assertNext("/some/stuff/more", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testGetB() {
+ final Iterator<String> rpi = new ResourcePathIterator(
+ "/some/stuff/more.html");
+ assertNext("/some/stuff/more.html", rpi);
+ assertNext("/some/stuff/more", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testHeadB() {
+ final Iterator<String> rpi = new ResourcePathIterator(
+ "/some/stuff/more.html");
+ assertNext("/some/stuff/more.html", rpi);
+ assertNext("/some/stuff/more", rpi);
+ assertFinished(rpi);
+ }
+
+ @Test public void testGetC() {
+ final Iterator<String> it = new ResourcePathIterator("/some/stuff/more");
+ assertNext("/some/stuff/more", it);
+ assertFinished(it);
+ }
+
+ @Test public void testGetD() {
+ final Iterator<String> it = new ResourcePathIterator(
+ "/some/stuff.print/more.html");
+ assertNext("/some/stuff.print/more.html", it);
+ assertNext("/some/stuff.print/more", it);
+ assertNext("/some/stuff", it);
+ assertFinished(it);
+ }
+
+ @Test public void testRelativePathGet() {
+ final Iterator<String> it = new ResourcePathIterator("some/stuff.print");
+ assertNext("some/stuff.print", it);
+ assertNext("some/stuff", it);
+ assertFinished(it);
+ }
+
+ private void assertNext(String expected, Iterator<String> iterator) {
+ assertTrue("Iterator must have next", iterator.hasNext());
+ assertEquals("Incorrect next value", expected, iterator.next());
+ }
+
+ private void assertFinished(Iterator<String> iterator) {
+
+ assertFalse("Iterator must not have next", iterator.hasNext());
+
+ try {
+ iterator.next();
+ fail("Iterator should throw NoSuchElementException");
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java
new file mode 100644
index 0000000..ffaf36d
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java
@@ -0,0 +1,266 @@
+/*
+ * 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.resourceresolver.impl.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceProviderFactory;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderFactoryHandler;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderHandler;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class SortedProviderListTest {
+
+ @Test public void testAddRemoveResourceProvider() {
+ final ResourceProviderImpl rp1 = new ResourceProviderImpl(null, 1L);
+ final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+ final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/hello"}, 3L);
+ final ResourceProviderImpl rp4 = new ResourceProviderImpl(new String[] {"/you"}, 4L);
+
+ final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+ check(spl, null);
+ spl.add(new ResourceProviderHandler(rp1, rp1.getProperties()));
+ check(spl, null);
+ spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+ check(spl, null, rp2);
+ spl.add(new ResourceProviderHandler(rp3, rp3.getProperties()));
+ check(spl, null, rp2, rp3);
+ spl.add(new ResourceProviderHandler(rp4, rp4.getProperties()));
+ check(spl, null, rp2, rp3);
+
+ spl.remove(new ResourceProviderHandler(rp1, rp1.getProperties()));
+ check(spl, null, rp2, rp3);
+ spl.remove(new ResourceProviderHandler(rp1, rp1.getProperties()));
+ check(spl, null, rp2, rp3);
+ spl.remove(new ResourceProviderHandler(rp4, rp4.getProperties()));
+ check(spl, null, rp2, rp3);
+ spl.remove(new ResourceProviderHandler(rp2, rp2.getProperties()));
+ check(spl, null, rp3);
+ spl.remove(new ResourceProviderHandler(rp3, rp3.getProperties()));
+ check(spl, null);
+ }
+
+ @Test public void testSortingRP() {
+ final AdaptableResourceProviderImpl rp1 = new AdaptableResourceProviderImpl(new String[] {"/d", "/a", "x"}, 1L);
+ final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+ final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/b"}, 3L);
+ final AdaptableResourceProviderImpl rp4 = new AdaptableResourceProviderImpl(new String[] {"/a/a"}, 4L);
+ final AdaptableResourceProviderImpl rp5 = new AdaptableResourceProviderImpl(new String[] {"/all/or/nothing"}, 5L);
+
+ final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+ check(spl, null);
+ spl.add(new ResourceProviderHandler(rp1, rp1.getProperties()));
+ check(spl, null, rp1);
+ spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+ check(spl, null, rp2, rp1);
+ spl.add(new ResourceProviderHandler(rp3, rp3.getProperties()));
+ check(spl, null, rp2, rp1, rp3);
+ spl.add(new ResourceProviderHandler(rp4, rp4.getProperties()));
+ check(spl, null, rp2, rp1, rp4, rp3);
+ spl.add(new ResourceProviderHandler(rp5, rp5.getProperties()));
+ check(spl, null, rp2, rp1, rp4, rp5, rp3);
+ }
+
+ @Test public void testAddRemoveResourceProviderFactory() {
+ final ResourceProviderImpl rp1 = new ResourceProviderImpl(null, 1L);
+ final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+ final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/hello"}, 3L);
+ final ResourceProviderImpl rp4 = new ResourceProviderImpl(new String[] {"/you"}, 4L);
+
+ final ResourceResolverContext ctx = new ResourceResolverContext(false, null);
+
+ final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+ check(spl, ctx);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+ check(spl, ctx);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+ check(spl, ctx, rp2);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+ check(spl, ctx, rp2, rp3);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+ check(spl, ctx, rp2, rp3);
+
+ spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+ check(spl, ctx, rp2, rp3);
+ spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+ check(spl, ctx, rp2, rp3);
+ spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+ check(spl, ctx, rp2, rp3);
+ spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+ check(spl, ctx, rp3);
+ spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+ check(spl, ctx);
+ }
+
+ @Test public void testSortingRF() {
+ final AdaptableResourceProviderImpl rp1 = new AdaptableResourceProviderImpl(new String[] {"/d", "/a", "x"}, 1L);
+ final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+ final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/b"}, 3L);
+ final AdaptableResourceProviderImpl rp4 = new AdaptableResourceProviderImpl(new String[] {"/a/a"}, 4L);
+ final AdaptableResourceProviderImpl rp5 = new AdaptableResourceProviderImpl(new String[] {"/all/or/nothing"}, 5L);
+
+ final ResourceResolverContext ctx = new ResourceResolverContext(false, null);
+
+ final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+ check(spl, ctx);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+ check(spl, ctx, rp1);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+ check(spl, ctx, rp2, rp1);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+ check(spl, ctx, rp2, rp1, rp3);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+ check(spl, ctx, rp2, rp1, rp4, rp3);
+ spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp5), rp5.getProperties()));
+ check(spl, ctx, rp2, rp1, rp4, rp5, rp3);
+ }
+
+ @Test public void checkExceptions() {
+ final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+
+ final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+ spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+
+ final Iterator<Adaptable> i = spl.getProviders(null);
+ assertTrue(i.hasNext());
+ i.next(); // one entry
+ assertFalse(i.hasNext());
+ try {
+ i.remove();
+ fail();
+ } catch (UnsupportedOperationException uoe) {
+ // expected
+ }
+ try {
+ i.next();
+ fail();
+ } catch (NoSuchElementException nsee) {
+ // expected
+ }
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * Helper method checking the order of the sorted array.
+ */
+ private void check(final SortedProviderList<Adaptable> spl,
+ final ResourceResolverContext ctx,
+ final Adaptable... objects) {
+ final int expectedCount = objects == null ? 0 : objects.length;
+ final Iterator<Adaptable> i = spl.getProviders(ctx);
+ int count = 0;
+ while ( i.hasNext() ) {
+ final Adaptable a = i.next();
+ assertEquals(objects[count], a);
+ count++;
+ }
+ assertEquals(expectedCount, count);
+ }
+
+ private static class ResourceProviderImpl implements ResourceProvider {
+
+ private final String[] roots;
+ private final Long serviceId;
+
+ public ResourceProviderImpl(String[] roots, Long serviceId) {
+ this.roots = roots;
+ this.serviceId = serviceId;
+ }
+
+ public Map<String, Object> getProperties() {
+ final Map<String, Object> props = new HashMap<String, Object>();
+ props.put(Constants.SERVICE_ID, serviceId);
+ props.put(ResourceProvider.ROOTS, roots);
+ return props;
+ }
+
+ public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
+ return null;
+ }
+
+ public Resource getResource(ResourceResolver resourceResolver, String path) {
+ return null;
+ }
+
+ public Iterator<Resource> listChildren(Resource parent) {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj instanceof ResourceProviderImpl ) {
+ return this.serviceId.equals(((ResourceProviderImpl)obj).serviceId);
+ }
+ return false;
+ }
+ }
+
+ private static class AdaptableResourceProviderImpl extends ResourceProviderImpl
+ implements Adaptable {
+
+ public AdaptableResourceProviderImpl(String[] roots, Long serviceId) {
+ super(roots, serviceId);
+ }
+
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ return null;
+ }
+ }
+
+ private static class ResourceProviderFactoryImpl implements ResourceProviderFactory {
+
+ private final ResourceProviderImpl resourceProviderImpl;
+
+ public ResourceProviderFactoryImpl(ResourceProviderImpl rpi) {
+ this.resourceProviderImpl = rpi;
+ }
+
+ public ResourceProvider getResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
+ return this.resourceProviderImpl;
+ }
+
+ public ResourceProvider getAdministrativeResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
+ return this.resourceProviderImpl;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj instanceof ResourceProviderFactoryImpl ) {
+ return this.resourceProviderImpl.equals(((ResourceProviderFactoryImpl)obj).resourceProviderImpl);
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java
new file mode 100644
index 0000000..72c2689
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.resourceresolver.impl.helper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.junit.Test;
+
+/** Test the StarResource */
+public class StarResourceTest {
+
+ private void assertSplit(String requestPath, String path, String pathInfo) {
+ final ResourceMetadata rm = StarResource.getResourceMetadata(requestPath);
+ assertEquals("For requestPath=" + requestPath + ", path matches", path, rm.getResolutionPath());
+ assertEquals("For requestPath=" + requestPath + ", pathInfo matches", pathInfo, rm.getResolutionPathInfo());
+ }
+
+ @Test public void testSimplePath() {
+ assertSplit("/foo/*.html", "/foo/*", ".html");
+ }
+
+ @Test public void testNoExtension() {
+ assertSplit("/foo/*", "/foo/*", "");
+ }
+
+ @Test public void testNoStar() {
+ assertSplit("/foo/bar.html", "/foo/bar.html", null);
+ }
+
+ @Test public void testTwoStars() {
+ assertSplit("/foo/*.html/*.txt", "/foo/*", ".html/*.txt");
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntryTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntryTest.java
new file mode 100644
index 0000000..918632d
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/MapEntryTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.resourceresolver.impl.mapping;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import junit.framework.TestCase;
+
+import org.apache.sling.resourceresolver.impl.mapping.MapEntry;
+import org.junit.Test;
+
+public class MapEntryTest {
+
+ @Test public void test_to_url_http_80() {
+ assertEqualUri("http://sling.apache.org", "http/sling.apache.org.80");
+ assertEqualUri("http://sling.apache.org/", "http/sling.apache.org.80/");
+ assertEqualUri("http://sling.apache.org/site/index.html",
+ "http/sling.apache.org.80/site/index.html");
+ }
+
+ @Test public void test_to_url_https_443() {
+ assertEqualUri("https://sling.apache.org", "https/sling.apache.org.443");
+ assertEqualUri("https://sling.apache.org/",
+ "https/sling.apache.org.443/");
+ assertEqualUri("https://sling.apache.org/site/index.html",
+ "https/sling.apache.org.443/site/index.html");
+ }
+
+ @Test public void test_to_url_any_999() {
+ // http with arbitrary port
+ assertEqualUri("http://sling.apache.org:123",
+ "http/sling.apache.org.123");
+ assertEqualUri("http://sling.apache.org:456/",
+ "http/sling.apache.org.456/");
+ assertEqualUri("http://sling.apache.org:456/site/index.html",
+ "http/sling.apache.org.456/site/index.html");
+
+ // https with arbitrary port
+ assertEqualUri("https://sling.apache.org:987",
+ "https/sling.apache.org.987");
+ assertEqualUri("https://sling.apache.org:654/",
+ "https/sling.apache.org.654/");
+ assertEqualUri("https://sling.apache.org:321/site/index.html",
+ "https/sling.apache.org.321/site/index.html");
+
+ // any scheme with arbitrary port
+ assertEqualUri("gurk://sling.apache.org:987",
+ "gurk/sling.apache.org.987");
+ assertEqualUri("gurk://sling.apache.org:654/",
+ "gurk/sling.apache.org.654/");
+ assertEqualUri("gurk://sling.apache.org:321/site/index.html",
+ "gurk/sling.apache.org.321/site/index.html");
+ }
+
+ @Test public void test_to_url_any() {
+ // http without port
+ assertEqualUri("http://sling.apache.org", "http/sling.apache.org");
+ assertEqualUri("http://sling.apache.org/", "http/sling.apache.org/");
+ assertEqualUri("http://sling.apache.org/site/index.html",
+ "http/sling.apache.org/site/index.html");
+
+ // https without port
+ assertEqualUri("https://sling.apache.org", "https/sling.apache.org");
+ assertEqualUri("https://sling.apache.org/", "https/sling.apache.org/");
+ assertEqualUri("https://sling.apache.org/site/index.html",
+ "https/sling.apache.org/site/index.html");
+
+ // any scheme without port
+ assertEqualUri("gurk://sling.apache.org", "gurk/sling.apache.org");
+ assertEqualUri("gurk://sling.apache.org/", "gurk/sling.apache.org/");
+ assertEqualUri("gurk://sling.apache.org/site/index.html",
+ "gurk/sling.apache.org/site/index.html");
+ }
+
+ @Test public void test_fixUriPath() {
+ // http without port
+ assertEqualUriPath("http/sling.apache.org.80", "http/sling.apache.org");
+ assertEqualUriPath("http/sling.apache.org.80/",
+ "http/sling.apache.org/");
+ assertEqualUriPath("http/sling.apache.org.80/site/index.html",
+ "http/sling.apache.org/site/index.html");
+
+ // http with port
+ assertEqualUriPath("http/sling.apache.org.80",
+ "http/sling.apache.org.80");
+ assertEqualUriPath("http/sling.apache.org.80/",
+ "http/sling.apache.org.80/");
+ assertEqualUriPath("http/sling.apache.org.80/site/index.html",
+ "http/sling.apache.org.80/site/index.html");
+
+ // https without port
+ assertEqualUriPath("https/sling.apache.org.443",
+ "https/sling.apache.org");
+ assertEqualUriPath("https/sling.apache.org.443/",
+ "https/sling.apache.org/");
+ assertEqualUriPath("https/sling.apache.org.443/site/index.html",
+ "https/sling.apache.org/site/index.html");
+
+ // https with port
+ assertEqualUriPath("https/sling.apache.org.443",
+ "https/sling.apache.org.443");
+ assertEqualUriPath("https/sling.apache.org.443/",
+ "https/sling.apache.org.443/");
+ assertEqualUriPath("https/sling.apache.org.443/site/index.html",
+ "https/sling.apache.org.443/site/index.html");
+
+ // anything without port
+ assertEqualUriPath("gurk/sling.apache.org", "gurk/sling.apache.org");
+ assertEqualUriPath("gurk/sling.apache.org/", "gurk/sling.apache.org/");
+ assertEqualUriPath("gurk/sling.apache.org/site/index.html",
+ "gurk/sling.apache.org/site/index.html");
+
+ // http with port
+ assertEqualUriPath("gurk/sling.apache.org.123",
+ "gurk/sling.apache.org.123");
+ assertEqualUriPath("gurk/sling.apache.org.456/",
+ "gurk/sling.apache.org.456/");
+ assertEqualUriPath("gurk/sling.apache.org.789/site/index.html",
+ "gurk/sling.apache.org.789/site/index.html");
+
+ }
+
+ @Test public void test_isRegExp() {
+ TestCase.assertFalse(isRegExp("http/www.example.com.8080/bla"));
+ TestCase.assertTrue(isRegExp("http/.+\\.www.example.com.8080/bla"));
+ TestCase.assertTrue(isRegExp("http/(.+)\\.www.example.com.8080/bla"));
+ TestCase.assertTrue(isRegExp("http/(.+)\\.www.example.com.8080/bla"));
+ TestCase.assertTrue(isRegExp("http/[^.]+.www.example.com.8080/bla"));
+ }
+
+ private void assertEqualUri(String expected, String uriPath) {
+ URI uri = MapEntry.toURI(uriPath);
+ assertNotNull("Failed converting " + uriPath, uri);
+ assertEquals(expected, uri.toString());
+ }
+
+ private void assertEqualUriPath(String expected, String uriPath) {
+ String fixed = MapEntry.fixUriPath(uriPath);
+ assertNotNull(fixed);
+ assertEquals(expected, fixed);
+ }
+
+ private boolean isRegExp(final String string) {
+ try {
+ Method m = MapEntry.class.getDeclaredMethod("isRegExp", String.class);
+ m.setAccessible(true);
+ return (Boolean) m.invoke(null, string);
+ } catch (Exception e) {
+ fail(e.toString());
+ return false; // quiesc compiler
+ }
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandlerTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandlerTest.java
new file mode 100644
index 0000000..5d2b08e
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandlerTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.resourceresolver.impl.tree;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class ProviderHandlerTest {
+
+ @Test public void testRoots() {
+ // service id = 1, no roots
+ final Map<String, Object> props1 = new HashMap<String, Object>();
+ props1.put(Constants.SERVICE_ID, 1L);
+ final ProviderHandler ph1 = new MyProviderHandler(props1);
+ assertNull(ph1.getRoots());
+ assertEquals(1, (long)ph1.getServiceId());
+
+ // service id = 2, empty roots
+ final Map<String, Object> props2 = new HashMap<String, Object>();
+ props2.put(Constants.SERVICE_ID, 2L);
+ props2.put(ResourceProvider.ROOTS, new String[0]);
+ final ProviderHandler ph2 = new MyProviderHandler(props2);
+ assertNull(ph2.getRoots());
+ assertEquals(2, (long)ph2.getServiceId());
+
+ // service id = 3, empty string
+ final Map<String, Object> props3 = new HashMap<String, Object>();
+ props3.put(Constants.SERVICE_ID, 3L);
+ props3.put(ResourceProvider.ROOTS, new String[] {""});
+ final ProviderHandler ph3 = new MyProviderHandler(props3);
+ assertNull(ph3.getRoots());
+ assertEquals(3, (long)ph3.getServiceId());
+
+ // service id = 4, empty string and real string mixed
+ final Map<String, Object> props4 = new HashMap<String, Object>();
+ props4.put(Constants.SERVICE_ID, 4L);
+ props4.put(ResourceProvider.ROOTS, new String[] {"", "/a", " ", "/a", "/b", "/c ", " /d ", ""});
+ final ProviderHandler ph4 = new MyProviderHandler(props4);
+ assertNotNull(ph4.getRoots());
+ assertEquals(4, (long)ph4.getServiceId());
+ assertEquals(new String[] {"/a", "/b", "/c", "/d"}, ph4.getRoots());
+
+ // service id = 5, trailing slash string
+ final Map<String, Object> props5 = new HashMap<String, Object>();
+ props5.put(Constants.SERVICE_ID, 5L);
+ props5.put(ResourceProvider.ROOTS, new String[] {"", " /", "/b/ ", " /c/", " /d/ ", ""});
+ final ProviderHandler ph5 = new MyProviderHandler(props5);
+ assertNotNull(ph5.getRoots());
+ assertEquals(5, (long)ph5.getServiceId());
+ assertEquals(new String[] {"/", "/b", "/c", "/d"}, ph5.getRoots());
+ }
+
+ private static final class MyProviderHandler extends ProviderHandler {
+
+ public MyProviderHandler(Map<String, Object> properties) {
+ super(properties);
+ }
+
+ @Override
+ public Resource getResource(ResourceResolverContext ctx, ResourceResolver resourceResolver, String path) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Resource> listChildren(ResourceResolverContext ctx, Resource parent) { // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+}
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntryTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntryTest.java
new file mode 100644
index 0000000..739ddcb
--- /dev/null
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntryTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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.resourceresolver.impl.tree;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.AbstractResource;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourceresolver.impl.tree.ProviderHandler;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderEntry;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderHandler;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class ResourceProviderEntryTest {
+
+ private ResourceProvider rootProvider;
+
+ private ResourceProviderEntry root;
+
+ @Before public void setUp() throws Exception {
+ rootProvider = new TestResourceProvider("/");
+ final Map<String, Object> props = new HashMap<String, Object>();
+ props.put(Constants.SERVICE_ID, (long)0);
+ root = new ResourceProviderEntry("/", new ResourceProviderHandler[]{ new ResourceProviderHandler(rootProvider, props)});
+ }
+
+ @Test public void testRootProvider() {
+ assertNull(root.getResource(null, null, "relpath"));
+ assertEquals(root, root.getResource(null, null, "/"));
+ assertEquals(root, root.getResource(null, null, "/rootel"));
+ assertEquals(root, root.getResource(null, null, "/rootel/child"));
+ assertEquals(root, root.getResource(null, null, "/apps/sling/sample/html.js"));
+ assertEquals(root, root.getResource(null, null,
+ "/apps/sling/microsling/html.js"));
+ }
+
+ @Test public void testAdd1Provider() {
+ String firstPath = "/rootel";
+ ResourceProvider first = new TestResourceProvider(firstPath);
+ final Map<String, Object> firstProps = new HashMap<String, Object>();
+ firstProps.put(Constants.SERVICE_ID, (long)1);
+ root.addResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+
+
+ assertEquals(root, root.getResource(null, null, "/"));
+ assertEquals(first, root.getResource(null, null, "/rootel"));
+ assertEquals(first, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(first, root.getResource(null, null, "/rootel/child"));
+ assertEquals(first, root.getResource(null, null, "/rootel/child/html.js"));
+ assertEquals(rootProvider, root.getResource(null, null,
+ "/apps/sling/sample/html.js"));
+ assertEquals(rootProvider, root.getResource(null, null,
+ "/apps/sling/microsling/html.js"));
+ }
+
+ @Test public void testAdd3Providers() {
+ String firstPath = "/rootel";
+ String thirdPath = "/apps/sling/sample";
+ String secondPath = firstPath + "/child";
+
+ ResourceProvider first = new TestResourceProvider(firstPath);
+ ResourceProvider second = new TestResourceProvider(secondPath);
+ ResourceProvider third = new TestResourceProvider(thirdPath);
+ final Map<String, Object> firstProps = new HashMap<String, Object>();
+ firstProps.put(Constants.SERVICE_ID, (long)1);
+ final Map<String, Object> secondProps = new HashMap<String, Object>();
+ secondProps.put(Constants.SERVICE_ID, (long)2);
+ final Map<String, Object> thirdProps = new HashMap<String, Object>();
+ thirdProps.put(Constants.SERVICE_ID, (long)3);
+
+ root.addResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+ root.addResourceProvider(secondPath, new ResourceProviderHandler(second, secondProps));
+ root.addResourceProvider(thirdPath, new ResourceProviderHandler(third, thirdProps));
+
+
+ assertEquals(rootProvider, root.getResource(null, null, "/"));
+ assertEquals(first, root.getResource(null, null, "/rootel"));
+ assertEquals(first, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child/html.js"));
+ assertEquals(third,
+ root.getResource(null, null, "/apps/sling/sample/html.js"));
+ Resource resource = root.getResource(null, null,
+ "/apps/sling/microsling/html.js");
+ assertEquals(rootProvider, resource);
+ }
+
+ @Test public void testAdd3ProvidersReverse() {
+ String firstPath = "/rootel";
+ String thirdPath = "/apps/sling/sample";
+ String secondPath = firstPath + "/child";
+
+ ResourceProvider first = new TestResourceProvider(firstPath);
+ ResourceProvider second = new TestResourceProvider(secondPath);
+ ResourceProvider third = new TestResourceProvider(thirdPath);
+ final Map<String, Object> firstProps = new HashMap<String, Object>();
+ firstProps.put(Constants.SERVICE_ID, (long)1);
+ final Map<String, Object> secondProps = new HashMap<String, Object>();
+ secondProps.put(Constants.SERVICE_ID, (long)2);
+ final Map<String, Object> thirdProps = new HashMap<String, Object>();
+ thirdProps.put(Constants.SERVICE_ID, (long)3);
+
+ root.addResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+ root.addResourceProvider(secondPath, new ResourceProviderHandler(second, secondProps));
+ root.addResourceProvider(thirdPath, new ResourceProviderHandler(third, thirdProps));
+
+ assertEquals(rootProvider, root.getResource(null, null, "/"));
+ assertEquals(first, root.getResource(null, null, "/rootel"));
+ assertEquals(first, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child/html.js"));
+ assertEquals(third,
+ root.getResource(null, null, "/apps/sling/sample/html.js"));
+ Resource resource = root.getResource(null, null,
+ "/apps/sling/microsling/html.js");
+ assertEquals(rootProvider, resource);
+ }
+
+ @Test public void testRemoveProviders() {
+ String firstPath = "/rootel";
+ String thirdPath = "/apps/sling/sample";
+ String secondPath = firstPath + "/child";
+
+ ResourceProvider first = new TestResourceProvider(firstPath);
+ ResourceProvider second = new TestResourceProvider(secondPath);
+ ResourceProvider third = new TestResourceProvider(thirdPath);
+ final Map<String, Object> firstProps = new HashMap<String, Object>();
+ firstProps.put(Constants.SERVICE_ID, (long)1);
+ final Map<String, Object> secondProps = new HashMap<String, Object>();
+ secondProps.put(Constants.SERVICE_ID, (long)2);
+ final Map<String, Object> thirdProps = new HashMap<String, Object>();
+ thirdProps.put(Constants.SERVICE_ID, (long)3);
+
+ root.addResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+ root.addResourceProvider(secondPath, new ResourceProviderHandler(second, secondProps));
+ root.addResourceProvider(thirdPath, new ResourceProviderHandler(third, thirdProps));
+
+ assertEquals(rootProvider, root.getResource(null, null, "/"));
+ assertEquals(first, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child/html.js"));
+
+ root.removeResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+
+ assertEquals(rootProvider, root.getResource(null, null, "/"));
+ assertEquals(rootProvider, root.getResource(null, null, "/rootel/sddsf/sdfsdf/html.js"));
+ assertEquals(rootProvider, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child/html.js"));
+
+ root.addResourceProvider(firstPath, new ResourceProviderHandler(first, firstProps));
+
+ assertEquals(rootProvider, root.getResource(null, null, "/"));
+ assertEquals(first, root.getResource(null, null, "/rootel/html.js"));
+ assertEquals(second, root.getResource(null, null, "/rootel/child/html.js"));
+ }
+
+ protected void assertEquals(ResourceProvider resProvider, Resource res) {
+ org.junit.Assert.assertEquals(resProvider, res.getResourceResolver());
+ }
+
+ protected void assertEquals(ResourceProviderEntry resProviderEntry,
+ Resource res) {
+ ProviderHandler[] resourceProviders = resProviderEntry.getResourceProviders();
+ for ( ProviderHandler rp : resourceProviders ) {
+ if ( rp.equals(res.getResourceResolver())) {
+ return;
+ }
+ }
+ fail();
+ }
+
+ // The test provider implements the ResourceResolver interface and sets
+ // itself on the returned resource. This way the assertEquals methods above
+ // may identify whether a resource has been returned from the expected
+ // ResourceProvider
+ private static class TestResourceProvider implements ResourceProvider, ResourceResolver {
+
+ private final String[] roots;
+
+ TestResourceProvider(String root) {
+ roots = new String[] { root };
+ }
+
+ public ResourceResolver clone(Map<String, Object> authenticationInfo) {
+ throw new UnsupportedOperationException("copy");
+ }
+
+ public Resource getResource(ResourceResolver resolver,
+ HttpServletRequest request, String path) {
+ return getResource(resolver, path);
+ }
+
+ public Resource getResource(ResourceResolver resolver, String path) {
+ return new TestResource(path, this);
+ }
+
+ public Iterator<Resource> listChildren(Resource parent) {
+ return null;
+ }
+
+ // just dummy implementation to mark our resources for the tests
+ public Iterator<Resource> findResources(String query, String language) {
+ return null;
+ }
+
+ public Resource getResource(String path) {
+ return null;
+ }
+
+ public Resource getResource(Resource base, String path) {
+ return null;
+ }
+
+ public String[] getSearchPath() {
+ return null;
+ }
+
+ public String map(HttpServletRequest request, String resourcePath) {
+ return null;
+ }
+
+ public String map(String resourcePath) {
+ return null;
+ }
+
+ public Iterator<Map<String, Object>> queryResources(String query,
+ String language) {
+ return null;
+ }
+
+ public Resource resolve(HttpServletRequest request, String absPath) {
+ return null;
+ }
+
+ public Resource resolve(HttpServletRequest request) {
+ return null;
+ }
+
+ public Resource resolve(String absPath) {
+ return null;
+ }
+
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return Arrays.toString(roots);
+ }
+
+ public boolean isLive() {
+ return true;
+ }
+
+ public void close() {
+ // nothing to do
+ }
+
+ public String getUserID() {
+ return null;
+ }
+
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ public Iterator<String> getAttributeNames() {
+ return Collections.<String> emptyList().iterator();
+ }
+ }
+
+ private static class TestResource extends AbstractResource {
+
+ private final String path;
+
+ private final ResourceResolver resourceResolver;
+
+ public TestResource(String path, ResourceResolver resourceResolver) {
+ this.path = path;
+ this.resourceResolver = resourceResolver;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public ResourceMetadata getResourceMetadata() {
+ return null;
+ }
+
+ public ResourceResolver getResourceResolver() {
+ return resourceResolver;
+ }
+
+ public String getResourceType() {
+ return null;
+ }
+
+ public String getResourceSuperType() {
+ return null;
+ }
+
+ public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+ return null;
+ }
+ }
+}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.