Introducing the Sling Paradigm: Everything is a Resource
Created: 22. December 2007
1 Current State
Currently Sling uses resources, servlets and scripts as follows:
Resourceinterface is mainly used to abstract JCR
ServletResolveruses an internal registration of servlets registered as OSGi services with the interface
javax.servlet.Servletand selects the servlet based on the resource type of the
Resourceof the request only.
ResourceResolverto find request handling scripts based on the resource type of the
Resourceof the request, the request selector string and the request method or request extension.
- Request processing filters are based on OSGi services registered with the interface name
- Error handling is implemented in the
ServletResolverimplementation using the same mechanism to find a servlet (or script) based on the response status code or the caught
Throwableas the pseudo request method name and using a different default error handling servlet.
This mechanism works rather good, but there are currently enhancement requests, which may not easily be implemented with the current concepts:
- Allow scripting of request processing filters. Implementing this requires special filter wrappers, which may select filter scripts.
- Enhance servlet selection to include the same parameters as script resolution, namely the request selector string and the request method or request extension. Implementing this would require replicating much of the code of the current
2 Enter the Sling Paradigm
To overcome the limitations we introduce the Sling paradigm
The Sling paradigm brings the paradigm of Java Content Repository API (JCR) Everything is Content to Sling.
This means, that every script, servlet, filter, error handler, etc. is available from the
ResourceResolver just like normal content providing data to be rendered upon requests. To enable this resource resolution and resources have to provide certain functionality:
- Allow registration of resources with the resource resolver. This is required to access servlets and filters registered as OSGi services through the resource resolver.
- Provide eventing mechanism to support caching and cache management
- Extend resource adapter mechanism, that is to provide extension to the
- Extend resource enumeration to include resources from various sources
3 Implementing the Sling Paradigm
3.1 Resource Provisioning
To be able to access resources from different locations through a single resource resolver, a new
ResourceProvider interface is added. A resource provider is able to provide resources below a certain location in the (virtual) resource tree. The resource resolver selects a resource provider to ask for a resource looking for a longest match amongst the root paths of the providers. If the longest match resource provider cannot find the requested resource, the provider with the second longest match is asked, and so forth.
Accessing the JCR repository is also implemented in the form of a resource provider. This JCR resource provider is registered at the root –
/ – of the (virtual) resource tree. Thus the JCR repository is always asked if, no more specific resource provider has the requested resource.
ResourceProvider interface is defined as follows:
Resource providers are registered as OSGi services under the name
org.apache.sling.api.resource.ResourceProvider providing the list of resource path roots as a service registration property with the name
ResourceResolver interfaces are defined with a method
adaptTo, which adapts the object to other classes. Using this mechanism the JCR session of the resource resolver calling the
adaptTo method with the
javax.jcr.Session class object. Likewise the node on which a resource is based can be retrieved by calling the
Resource.adaptTo method with the
javax.jcr.Node class object.
To use resources as scripts, the
Resource.adaptTo method must support being called with the
org.apache.sling.api.script.SlingScript class object. But of course, we do not want to integrate the script manager with the resource resolver. To enable adapting objects to classes which are not foreseen by the original implementation, a factory mechanism is used. This way, the script manager can provide an adapter factory to adapt
Adaptable interface defines the API to be implemented by a class providing adaptability to another class. The single method defined by this interface is
This method is called to get a view of the same object in terms of another class. Examples of implementations of this method is the Sling
ResourceResolver implementation providing adapting to a JCR session and the Sling JCR based
Resource implementation providing adapting to a JCR node.
SlingAdaptable class is an implementation of the
Adaptable interface, calls the
AdapterManager (see below) to provider an adapter to the
SlingAdaptable object to the requested class. This class may be extended to have extensible adapters not foreseen at the time of the class development.
An example of extending the
SlingAdaptable class will be the Sling JCR based
Resource implementation. This way, such a resource may be adapted to a
SlingScript by means of an appropriatley programmed
AdapterFactory (see below).
AdapterFactory interface defines the service interface and API for factories supporting extensible adapters for
SlingAdaptable objects. The interface has a single method:
This method is called by the
AdapterManager on behalf of the
SlingAdaptable object providing the
SlingAdaptable as the
adaptable parameter the requested class as the
type parameter. Implementations of this interface are registered as OSGi services providing two lists: The list of classes wich may be adapted and the list of classes to which the adapted class may be adapted.
AdapterManager is an internal class used by the
SlingAdaptable objects to find an
AdapterFactory to delegate the
adaptTo method call to. To make the
AdapterManager available globally, it is actually defined as a service interface. Thus the adapter manager may be retrieved from the service registry to try to adapt whatever object that needs to be adapted - provided appropriate adapters exist.
AdapterManager interface is defined as follows:
3.3 Change Events
ResourceResolver implementation defines events to be fired on changes in the (virtual) resource tree:
- All repository events are forwarded
- Resource provider addition and removal events are generated
Events are transmitted using the OSGi EventTracker specification. That is interested parties must register as OSGi event listener services.
3.4 Resource Enumeration
To be help in development and debugging and also to merely visualize the (virtual) resource tree, the resource tree must be explorable. That is, for every resource, the method
ResourceResolver.listChildren(Resource resource) method must return all resources which may be considered children of the given resource.
Consider for example the following (partial) repository:
Further consider the filter FilterC registered as an OSGi service. Thus the
listChildren call for the resource at
/filters/request must return three resources
/filters/request/FilterC. The first two will be JCR based resources, while the latter will be a servlet resource.
4 Employing the Sling Paradigm
4.1 Resources in Bundles
Resources may be located in OSGi bundles and mapped into the (virtual) resource tree by means of a
BundleResourceProvider. Bundles containing resources indicate this fact by means of a special bundle manifest header:
Sling-Bundle-Resources. Two notes regarding bundle resources:
- Bundle entries are either files or directories. To have these files and directories be handled as if they would be file and folder nodes in a repository, bundle based files will have a resource type
nt:fileand bundle based directories will have a resource type
- Bundle resource may be anything which may be represented by a file (or directory). That is the resources may be static content to be delivered to clients on request or resources may be scripts to be called to handle requests (or filter scripts even).
Servlets to be used for request processing are registered as OSGi services with a series of required service registration properties:
servlet.name- The name of the servlet as returned from
ServletConfig.getServletName(). If this property is not set, the
service.idproperties are checked in order.
servlet.path- A list of absolute paths under which the servlet is provided in the (virtual) resource tree.
sling.servlet.paths- The name of the service registration property of a Servlet registered as a service providing the absolute paths under which the servlet is accessible as a Resource (value is "sling.servlet.paths"). The type of this property is a String or String (array of strings) denoting the resource types.
sling.servlet.resourceTypes- The name of the service registration property of a Servlet registered as a service containing the resource type(s) supported by the servlet (value is "sling.servlet.resourceTypes"). The type of this property is a String or String (array of strings) denoting the resource types. This property is ignored if the
SLING_SERVLET_PATHSproperty is set. Otherwise this property must be set or the servlet is ignored.
sling.servlet.selectors- The name of the service registration property of a Servlet registered as a service containing the request URL selectors supported by the servlet (value is "sling.servlet.selectors"). The selectors must be configured as they would be specified in the URL that is as a list of dot-separated strings such as print.a4. The type of this property is a String or String (array of strings) denoting the resource types. This property is ignored if the
SLING_SERVLET_PATHSproperty is set. Otherwise this property is optional and ignored if not set.
sling.servlet.extensions- The name of the service registration property of a Servlet registered as a service containing the request URL extensions supported by the servlet for GET requests (value is "sling.servlet.extensions"). The type of this property is a String or String (array of strings) denoting the resource types. This property is ignored if the
SLING_SERVLET_PATHSproperty is set. Otherwise this property or
SLING_SERVLET_METHODSmust be set or the servlet is ignored.
sling.servlet.methods- The name of the service registration property of a Servlet registered as a service containing the request methods supported by the servlet (value is "sling.servlet.methods"). The type of this property is a String or String (array of strings) denoting the resource types. This property is ignored if the
SLING_SERVLET_PATHSproperty is set. Otherwise this property or
SLING_SERVLET_EXTENSIONSmust be set or the servlet is ignored.
SlingServletResolver will listen for
Servlet services and - given the correct service registration properties - provide the servlets as resources in the (virtual) resource tree. Such servlets are provided as
ServletResource instances which adapt to the
Filters may be provided in two different ways: As
javax.servlet.Filter instances registered as OSGi services and as scripts located in a predefined place. When requests are processed the filters are looked up in the (virtual) resource tree below the
/filters node. The list of filters is comprised of all the filters directly below the respective scope – request or resource – and the those below the respective scope and the type of the resource of the request.
The filters are sorted by their names. Hence a convention for the names of the filters in the (virtual) resource tree is defined such that the names is composed of an ordering number and the actual filter name, e.g. 0_sample.
4.3.1 Filter Services
Filters registered as OSGi services have three required service registration properties:
filter.scope- (String) Scope of the filter, which must be either request or resource
filter.order- (Integer) Call order of the filter used to define the filter call sequence
filter.name- (String) The name of the filter as returned
FilterConfig.getFilterName(). If this property is not set, the
service.idproperties are checked in order.
filter.resource.type- (String) The list of resource types to which this filter applies. This property is optional. If missing, the filter applies to all resource types. If this property is an empty list, the filter is not used as it applies to an empty list of resource types.
Such Filter services are added to the (virtual) resource tree at a path defined as follows for each resource type
resource_type listed in the
filter.resource.type property is missing, the filter is added at
4.3.2 Filter Scripts
Filter scripts may just be added as resources in the JCR repository at the appropriate location. For example for a request level filter applicable to
nt:file nodes only, the filter would be placed in the
4.4 Scripts from Resource
Resource returned from the resource resolver may be a script. The script manager registers an
AdapterFactory to adapt
SlingScript. This factory will resolve a script engine for the resource file extension and return a
SlingScript instance based on the
Resource. If no script engine exists, the
Resource may not be adapted.
AdapterFactory adapting to a
SlingScript is also able to adapt to
Servlet by wrapping the adapted
SlingScript in a
h3 4.5 Object Content Mapping
To cope with the new extensible functionality based on the
SlingAdaptable class and adapter factories, object content mapping cannot be hard coded to just respond to any class. Instead, the Object Content Mapping functionality is in fact provided in terms of adapter factories, which are registered to be able to adapt instances the
Resource interface to predefined types.
This way, Object Content Mapping takes part in adapter resolution just like any extensible adaption.
As a consequence, Object Content Mapping may probable be taken out of the current
jcr/resource project into its own project.
5 Changes to the Code
5.1 Sling API
RespourceResolverinterfaces extend the
5.2 OSGi Commons
org.apache.sling.osgi.commons bundle is a new project providing the following functionality:
ServiceLocatorimplementation (moved from
ServletResolver interfaces are merged into a single
ServletResolver interface, which has a
resolve(SlingHttpServletRequest) and a
find(ResourceResolver, String relPath) method. The implementation of this method will apply the alogirthm of the current
scripting/resolver implementation of the
Any script (or servlet or actually code) may call any script or servlet by just resolving the script or servlet to a
Resource and adapting the resource found to a
5.4 Separate Object Content Mapping from Resource Resolution
By applying the mechanisms of adapter factories, Object Content Mapping can be broken out of the
jcr/resource project into its own project
5.5 Enhance Sling Console
Provide a Sling Console enhancement to explore the (virtual) resource tree
5.6 Create New Adapter Project
A new Adapter project
sling/adapter takes the following classes:
Adaptableand leveraging adapter factories
- Implementation of the
AdapterManagerservice also used by