New concept for a resource abstraction layer in Pustefix
Introduction
At the moment (January 2009) Pustefix knows different kinds of resources: files, images, text parts, XML / XSL documents, etc. Although some of these resources are using a common infrastructure, there is no global abstraction layer for all kinds of resources.
In order to improve Pustefix's module support, there needs to be some kind of abstraction layers that allows resources to be loaded from various sources, without having to handle each resource type independently.
Requirements
- There are at least two types of resources: Resources that are local to the project and resources that are provided by shared modules.
- Other sources for resources (e.g. databases, WebDAV) can be added easily without changing the architecture or client code.
- Each resource is identified by at least one URI. There may be more than one URI representing the same resource.
- The object representing a resource in the programming model must provide a method that returns exactly the URI that was used to retrieve this object representing the resource. It must also provide a method that returns a URI that will point to this and only this resource. The object may provide additional URIs that point to the same resource.
- Resources from different sources can be made available within the same name space / path in order to make the source of a given resource transparent to the code accessing this resource.
- There may be more than one resource being present for a given URI.
- If there is more than one resource for a given URI, a mechanism that allows for easy selection of the most suitable resource has to be provider. That mechanism selects the resource that matches best regarding various parameters.
Concept
- Different sources are represented by different resource providers. Each resource provider has an URI scheme that is associated with this provider.
- A resource provider may delegate the lookup process to a different resource provider by using the associated scheme.
- A resource can have various attributes. These attributes are used by selectors to select the "best" resource when more than one resource is available for a given URI.
- These selectors are always executed in the same, fixed order, thus providing an order for different attributes. The selectors may use parameters provided with the request for the resource.
- The type of a resource is represented by the type of the object representing the resource in the programming model.
Resource types
A resource implementation may implement various interfaces, depending on which kind of data and meta information it provides. We need at least the following types of resources:
- InputStreamResource: Provides the resource's data through an input stream.
Besides the following types of resources might be useful:
- DOMDocumentResource: Provides a DOM Document instance
- DOMElementResources: Provides a DOM Element instance
- TemplatesResource: Provides the compiled representation of an XSLT stylesheet
- ThemedResource: Provides meta information about the "themes" provided by the resource
- InternationalizedResource: Provides meta information about the language a resource is providing
- OutputStreamResource: Allows to change the resource's content using an output stream
Resource Providers
- Resource Providers provide access to resources for a specific scheme.
- They are registered as services, storing the supported scheme(s) in an OSGi service property, for easy filtering.
Resource Selectors
- Resource Selectors are registered as services.
- They can have an order (by using a numeric value). If they have no or two share same order, they are used in order of registration.
Request parameter
- Request parameters should provide a method to serialize them to strings in order to be able to store them in the query string of an URI.
Examples
These are some examples of how the URIs might look like:
- pfixroot:/modules/foo/bar might be delegated to the module resource provider using the URI module:/foo/bar and to the project resource provider using a URI like project:/overload/bar
- pfixroot:/bar might be delegated to the project local resource provider using the URI project:/bar
- targetgenerator:target.xml might be handled by the target generator of the project, returning an XML target
