API Enhancement: Add ResourceResolverFactory
Easier and more flexible access to ResourceResolver instances providing the ResourceResolverFactory interface in the Sling API and allow for the extensibility of the factory using new ResourceResolverProvider services. (IMPLEMENTED)
Created: 9. November 2008
JIRA: SLING-1262 and SLING-2396
Updated: 17. November 2008, fmeschbe, Added Section 5.2
Updated: 05. July 2012, cziegele, Implemented with some additions as outlined in SLING-2396
|Table of Contents|
1 Current State
The Sling API currently only defines the
ResourceResolver interface but not how such a resolver is to be created/retrieved.
In addition the Sling implementation has:
- [Sling] Repository providers, which just register one or more repository instances as services
JcrResourceResolverFactoryservice which creates
ResourceResolverinstances based on JCR Session objects
- The authenticator selects one of the Repository services to authenticate against and creates the Session to get the
This implementation has a series of drawbacks:
- The authenticator decides which repository to access: Problem is, that the authenticator is most probably not the right instance to decide on this issue.
- Getting a Resource resolver is tedious in that a Session is first to be created and then a resolver can be retrieved from the factory
- Only a single workspace of a single repository may be accessed at a any time and the authenticator actually defines which of those.
- All in all, this decouples the ResourceResolverProvider too much from the repository and gives the authenticator too much "power"
Therefore I propose the extension of the Sling API as presented herein.
2 Extensions at a Glance
This is the list of additions, I propose for the Sling API. Please refer to then following sections for more details, description and motivation.
ResourceResolverFactoryservice interface which provides a
ResourceProviderFactoryservice interface to help
- Add lifecyle support to the
LoginExceptionto support failure reporting in the
ResourceResolverFactory is provided by the Sling framework as a service. The factory provides a single method
ResourceResolver getResourceResolver(Map<String, Object> credentials) throws LoginException;
This method uses the credentials object to authenticate the user and to create
ResourceResolver instances, which may then be used to access resources. If authentication fails, a
LoginException (see below) is thrown.
Authentication fails if at least one
ResourceProviderFactory service which is registered with the
provider.required property set to
true throws a
LoginExcdeption. This for example allows multiple
ResourceProviderFactory services to be registered to access the JCR repository, each for a different location/workspace and one factory service to be the one to decide, whether authentication succeeds or not.
ResourceResovlerFactory services not having the
provider.required property set to true will just be ignored if they cannot return a
ResourceResolver interface is extended with a new method
which must be called when the resource resolver is no longer used. This allows for any cleanup required in the
ResourceProvider instances attached to the resource resolver.
ResourceResolverFactory will return a
ResourceResolver which behind the scenes makes use of
ResourceProvider instances. This interface already exists today and is implemented to access bundle or filesystem resources. Actually repository access is internally also implemented as a
To allow for authenticated
ResourceProvider instances in addition to unauthenticated ones, a new factory interface
ResourceProviderFactory is introduced which provides a single method:
// Creates a normal resource provider using credentials // to indicate the user to login as. ResourceProvider getResourceProvider(Map<String, Object> credentials) throws LoginException; // Creates an administrative resource provider. Any user // credentials are ignored. The ResourceProvider is assumed // to have administrative (aka root aka superuser) rights // on the resources provided. // This method is targeted as background services and not // intended for normal request processing. ResourceProvider getAdministrativeResourceProvider(Map<String, Object> credentials) throws LoginException; // Creates an anonymous resource provider. Any user // credentials are ignored. The ResourceProvider is assumed // to have restricted (read-only mostly) rights on the // resources provided. This factory method may be used to // implemented guest access to the system. // This method is targeted as background services. It may // also be used by authenticators to support anonymous access // to the system in a public site where authentication is // the exception rather than the rule. ResourceProvider getAnonymousResourceProvider(Map<String, Object> credentials) throws LoginException;
This method returns a resource provider with the given credentials or throws a
LoginException if the credentials do not allow access to the resources provided by the
ResourceProviderFactory is a service interface and as such the registered
ResourceProviderFactory services have the following defined service registration properties:
provider.roots– Defines the root paths under which the ResourceProvider is attached into Resource tree. This is the same property as for the
ResourceProviderservice and applies to all
ResourceProviderinstances created by the factory.
provider.required– Indicates whether the
ResourceProviderinstances provided by the
ResourceProviderFactoryhave to be assumed as required. Failing to create as
ResourceProviderwith this factory, will cause the
ResourceResolverFactory.getResourceResolver()method to fail if this property is set to the boolean value
Since I cannot assume all real-world use cases right now and do not want to tie the Sling API into any specific use case, I propse the credentials to simply be a
Map<String, Object> object. To simplify use, though, a few predfined entries are defined in the
user.name(String) – The name of the user to connect as to resource providers.
user.password(String) – The password supplied by the user to connect to resource providers.
user.workspace(String) – This convenience property may be used to hint at a primary workspace to connect to.
user.session(javax.jcr.Session) – This property is primarily present to implement backwards compatibility for the
JcrResourceResolverFactoryinterface. If this property is provided,
ResourceProviderFactoryservices may wish to ignore any other properties and just use the JCR Session.
Other properties may of course be supplied and depend mainly on
ResourceProviderFactory services, which may require or use them. Generally, though, providing the
user.password properties should suffice it.
5.2 SlingRepository and AbstractSlingRepository
SlingRepository interface and the
AbstractSlingRepository abstract class currently provide support for getting administrative and anonymous sessions to the repository. Access details for such sessions is to be configured with the
With the implementation of a
ResourceResolverFactory and its accessor methods for acquiring administrative and anonymous access, the respective
AbstractSlingRepository methods become superfluous.
In addition the
SlingRepository.getDefaultWorkspace() method is probably also not required since, it is either the underlying actual JCR repository defining the default workspace or any JCR based
ResourceProvider which defines which workspace to access.
As a consequence the
SlingRepository interface and support for administrative and anonymous access to a repository in the
AbstractSlingRepository may be phased out.
However, for some time, we might have to provide backwards compatibility:
SlingRepository.getDefaultWorkspace()– Implemented by
AbstractSlingRepository; always returns
SlingRepository.loginAdministrative()– Implemented by
ResourceResolverFactory.getAdministrativeResourceResolver()and returns a
Sessionwhich on logout also closes the
AbstractSlingRepository.login(null, workspace)– Implemented by
ResourceResolverFactory.getAnonymousResourceResolver()and returns a
Sessionwhich on logout also closes the
jcr/jackrabbit-clientmodules do not register
SlingRepositoryinstances anymore but the actual
Repositoryinstance as a
SlingRepositoryservice is registered by a backwards compatibility class, probably related to the actual
Alternatively, it might also be decided to drop
SlingRepository altogether form Sling.
To allow for
ResourceProvider instances returned by
ResourceProviderFactory services to be cleaned up when no longer used, a new method is added to the
This method must close the
ResourceProvider and cleanup any resources used. For example a JCR based
ResourceProvider will logout the underlying session upon close.
This method will have no effect if called on a
ResourceProvider which is registered as a service. For example the
BundleResourceProvider will implement an empty
close() method is not expected to throw any exception at all. If some error occurrs while processing cleanup, the method is expected to implement error processing, which might be logging a message or just to ignore the situation.
LoginException extends the existing
SlingException and therefore is an unchecked
RuntimeException. This exception may be thrown by the
ResourceResolverFactory.getResourceResolver() methods to indicate failure to connect to any resources. The exception should provide a descriptive message as well as any cause which led to the
8 Logging into the System
To log into the system, the authenticator will extract the credentials from the HTTP request and call the
ResourceResolverFactory.getResourceResolver method with the credentials. If the
ResourceResolverFactory throws a
LoginException, authentication fails.
9 Changes in Sling
- The existing
JcrResourceResolverFactoryinterface is deprecated
JcrResourceResolverFactoryImplclass is turned in to a
ResourceProviderFactory, which accepts JCR Session instances in the credentials as the base for creating a
- A new implementation of the
JcrResourceResolverFactoryinterface is created, which just relates to the
ResourceResolverFactory.getResourceResolver()method providing the JCR Session as the only credentials entry.
- The jcr/resource module is split into two modules:
JcrResourceResolverclasses are moved to a new module implementing the
- The jcr/resource module keeps the exported classes and interfaces in the
o.a.s.jcr.resourcepackage as well as the internal implementations of the JCR support for the Sling Resource API
Existing code may still use the
JcrResourceResolverFactory service to get a
ResourceResolver. Still it is expected and proposed for this existing code to migrate to the new API over time. Existing code in the Sling project will be migrated to the new API as soon as it is available. New code should use the new