An issue has been raised whilst exploring the versioning implementation that isn't necessarily restricted to versioning - There are a core set of services (i.e. node, content, search) that effectively wrap the notion of a store. So far, we've considered workspace implementations of these services. However, it would be useful to expose the same service api's for nodes that aren't necessarily in a workspace. For example, in the versioning case, we may need to access nodes held within a separate version store. How do we support this? One possible idea is the notion of Node References and Store Protocols which this page describes.
In our service api definitions so far, each method either has a single parameter indicating the workspace to operate within, or a pair of parameters which indicate the workspace and a specific node within the workspace to operate on.
The workspace and node are currently identified by strings, but we're changing them to a type that's more specific e.g. ID or Reference. Also, we're considering the notion of a workspace/node composite reference e.g. NodeReference(workspace, nodeid) which encapsulates the full location of a Node.
Node Reference (NodeRef)
I think we can take the notion of a Node Reference one stage further. The above scheme assumes that the Node actually resides in a Workspace. For most of the time, this is probably acceptable. However, this may not always be the case. The example so far, is that of versioning. Versioned nodes are not necessarily held in a Workspace form. In fact, for sophisticated version stores, it may be better to use a custom store. Even so, from a client's perspective, when retrieving properties and content of a versioned node, the existing NodeService and ContentService api's are well known and do the job well. Searching a versioned store is also satisfied by the SearchService. Alas, this can't be done as the current Service API's assume a Workspace implementation. A solution is that we introduce a NodeRef.
A NodeRef is comprised of:
StoreRef - identifier of store where Node resides
NodeID - identifier of Node within store
A store is any place where Nodes can be found (and optionally written). Example stores are:
A store doesn't necessarily have to represent a physical location - it could also be virtual e.g. Search Scope.
Where our Service API's currently accept a Workspace ID, instead they'll accept a StoreRef. And where they accept a Node ID, instead they'll accept a NodeRef.
The Repository maintains a registry of known store protocols. Service Implementors (i.e. technical folk) maintain the registry.
Protocol Specific Service Implementations
For each public Repository Service API, one or more service implementations can be registered (in the public service registry) where each implementation is mapped to a store protocol. For example, the NodeService API could be served by two implementations; one to support the workspace protocol and one to support the version protocol. By default, a single implementation is mapped to workspace.
A client of the Repository discovers and gains access to a Service API through the Repository Service Locator. Based on the mapping of service implementation to store protocol, it is possible for the service locator to return an interface onto a 'protocol redirector proxy', rather than directly onto a service implementation component.
The job of the 'protocol redirector proxy' is to intercept calls on the service interface, analyze the store or node reference passed **, and redirect the call to the appropriate service implementation. This means a client can be provided with Store/Node references and call Repository services without knowledge of where Nodes actually reside behind the Repository facade.
** the assumption here is that there is a convention followed when defining service api's with regards to how Store and Node references are intercepted.
Example client / service interaction:
Client is given the NodeRef workspace://default/file1 from the Search Service
Client invokes NodeService.getProperties('workspace://default/file1') and recieves properties of working copy
Client recieves Version History structure consisting of NodeRefs pointing to Version Nodes
Client picks out last Version Node in history i.e. 'versionstore://main/file1v5'
Client invokes NodeService.getProperties('versionstore://main/file1v5') and receives properties of v5
The above example assumes two implementations of the Node service. The first is fully aware of our Workspace implementation and uses Hibernate to gain access to node properties inside the database. The second is SubVersion based and has knowledge of how to map 'file1v5' to a specific Subversion entry whose revision is 5 and extract properties from it.
In the case where we implement our own Version Store as a Workspace, we can either return 'workspace://version/id' handles which point directly to the workspace that represents the version store or (preferably) map the Workspace Node Service implementation to both workspace and versionstore protocols. The second is preferable for bookmarking purposes.
Store protocols could allow us to support:
Different content back-ends e.g. workspace:, file:, ...
Search spaces e.g. workspace:, version: searchscope:, ... Note: The searchscope: protocol could allow for a custom search service implementation to work against a named set of aggregated indexes.
JSR-170 e.g. jcr:
Node References as Bookmarks?
A Node Reference is effectively a URL. There's no reason why it couldn't remain static over the lifetime of the Node. As such, it could be held by clients for later retrieval.
The only issue could be a changing Store Id. But this only occurs if the id represents a physical location e.g. the svn repository URL. Service implementations should provide logical names and keep an internal logical to physical mapping. This means that physical stores could actually move without affecting the Node Reference.
Could this be the basis for remote node references? Provide a remote store protocol?
Regardless of whether we go with this approach or not our Service API definitions should utilise the StoreRef and NodeRef types. To start with we'll only support the workspace protocol. However, in the future, if we decide, we can plug-in support for different protocols without affecting the public Service API's and client interaction.