JSR-170 Original but now Deprecated Info


Information below this point is deprecated

JSR-170 Implementation of ContentHostingService.

During the Summer of 2006, I did a JSR-170 Implementation of ContentHostingService as a prototype against the then Trunk 2.2 ContentHostingService. The implementation took the ContentHostingService API and re-implemented it using JSR-170 under the covers. It was done in in such a way as to allow JSR-170 clients (eg WebDAV implementations) to use the JSR-170 API directly and still obey the Sakai AuthZ implementation.

At the time the implementation was tested against the Resources Tool and the existing Sakai WebDAV fairly extensively by dropping large quantities of files into a mounted WebDAV folder in Tiger.

The Implementation can be found in contrib at https://source.sakaiproject.org/contrib/tfd/trunk/jackrabbit-contenthostingservice/
Its all licensed under ECL and uses Jackrabbit as the underlying 170 implementation.

The terms JSR-170 and JCR are interchangeable

Structure

The ContentHostingService sits on-top of a JCRAdapter that connects it to the JCR implementation. The Content Entities have JCR implementations that are delivered from the JCRAdapter. Specialization to Jackrabbit is performed in the org.sakaiproject.content.jcr.jackrabbit package, which deals with the JAAS based integration between the JCR and Sakai and the configuration of the types within the JCR.

The JCR implementations of ContentEntity, ContentResoruce and ContentCollection use a write through cache associated for properties associated with the node structure under a JCR node, this enables the JRC versions to appear to have exactly the same Hashtable structure of entities allowing these entities to be propagated outside the CHS and used in place whilst maintaining the transaction state.

Security

JSR-170 has the concept of a security manager, this manager is a JAAS based implementation that allows JCR sessions to authenticate and inject a JAAS credential into the request cycle. Where the requests are coming in through the CHS, the sessions remain active and bound to threads, so that the credential is a special system credential. When the Security manager is consulted, the assertion wires through to the SakaiSecurutyService to make realm based assertions on JCR operations which are mapped to Sakai functions. If the access is not via the CHS interface, there is no gateway security service, so the JAAS credential is new for each request and bound to the Sakai use in question. Again when Security assertions are made, they are made via the SakaiSecurityService so all of Sakai's existing security infrastructure is obeyed.

With the introduction of Group permissions resolutions within Sakai 2.2 CHS the security assertions became re-entrant under CHS. This is not a problem for CHS since it acts as a gateway security service. However since the JCR implements a lower level Security manager on each JCR node, this causes re-entrant behavior when group permissions are resolved. To avoid issues in this area a SecurityAdviser is used to allow attempts to resolve security issues from within the SecurityManager itself to bypass security assertions. This behavior eliminates infinite recursive loops and mimics the behavior of CHR. It does not in any way relax the existing security model.

Configuration and Storage

The structure outlines above is constructed by spring on startup. The JCR implementation is configured using a JCR specific configuration file. In my case this is a Jackrabbit configuration file. This allows a number of persistence managers for both main storage and versions to be chosen, as well as determining if versioning will be configured. In the Jackrabbit version the main Persistence Manager uses mysq/oracle/hsql whilst the bulk storage is on disk. Versioning is turned on, although the current CHS has no concept of versioning.

Node Types

To make a JCR work it needs to have Node Types defined. These specify how data is store and what the validation criteria are on the nodes. There are a limited number of standard node schema available for things like DAV. Where these exist they have been used to ensure that standard JCR clients continue to operate. In addition new Sakai nore type schema have been developed to enable the Sakai properties to be stored within the JCR node structure.

Sakai JCR Namespaces
sakai:http://www.sakaiproject.org/CHS/jcr/sakai/1.0
CHEF:http://www.sakaiproject.org/CHS/jcr/chef/1.0
DAV:http://www.sakaiproject.org/CHS/jcr/dav/1.0
sakaijcr:http://www.sakaiproject.org/CHS/jcr/jackrabbit/1.0

The DAV namespace in the above list is mapped to the standard DAV namespace in Jackrabbit to ensure the standard DAV application continues to work.

Sakai CHS Node Type Schema
<?xml version="1.0" encoding="UTF-8"?>
<nodeTypes xmlns:nt="http://www.jcp.org/jcr/nt/1.0" 
      xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" 
        xmlns:sv="http://www.jcp.org/jcr/sv/1.0" 
  xmlns:sakaijcr="http://www.sakaiproject.org/CHS/jcr/jackrabbit/1.0" 
  xmlns:CHEF="http://www.sakaiproject.org/CHS/jcr/chef/1.0" 
  xmlns:DAV="http://www.sakaiproject.org/CHS/jcr/dav/1.0" 
  xmlns:mix="http://www.jcp.org/jcr/mix/1.0">
  
  <!-- Adding this mixin to a node autocreates a child node called
          sakaijcr:properties to which you can add any property.
  But you mist register the namespace of any properties that are going to obe added. -->
  <nodeType name="sakaijcr:properties-mix" isMixin="true" 
          hasOrderableChildNodes="false" primaryItemName="">
    <supertypes>
      <supertype>mix:versionable</supertype>
    </supertypes>
    <childNodeDefinition name="sakaijcr:properties" 
        autoCreated="true" defaultPrimaryType="sakaijcr:properties-node" 
              mandatory="true" onParentVersion="COPY" 
             protected="false"  sameNameSiblings="false"  />
  </nodeType>
  <nodeType name="sakaijcr:properties-node" isMixin="false" 
          hasOrderableChildNodes="false" primaryItemName="">
    <supertypes>
      <supertype>mix:versionable</supertype>
      <supertype>nt:base</supertype>
    </supertypes>
    <propertyDefinition name="*" requiredType="undefined" 
           autoCreated="false" mandatory="false" onParentVersion="COPY"
              protected="false" multiple="false" />
    <childNodeDefinition name="*" defaultPrimaryType="nt:unstructured" 
          autoCreated="false" mandatory="false" onParentVersion="COPY" 
                     protected="false" sameNameSiblings="false">
      <requiredPrimaryTypes>
        <requiredPrimaryType>nt:base</requiredPrimaryType>
      </requiredPrimaryTypes>
    </childNodeDefinition>
  </nodeType>
</nodeTypes>

Performance

Since the 170 implementation is a thin shim over the top of a 170 implementation, the performance is largely a function of the underlying 170 implementation. In the tests that have done, a 170 implementation based on Jackrabbit appears to show performance improvements over the standard CHS. This observation is subjective so can be taken with a 'pinch of salt'.

Limitations

Although the implementation is storing content in the Database and on Disk it will not cluster, this is due to Jackrabbit not clustering. There are Feature Request against Jackrabbit 1.0 to make it cluster, although these appear to be being resolved by replication rather than clustering. So as it stands, the implementation is a prototype only.

There are however a number of large Content Management solutions about that have some form of 170 interface, and it should be possible for those commercial companies to port this code to make their 170 implementation work under Sakai. So far I have heard interest from Harvest Road and Zythos, but I have not seen implementations. Others might include Alfresco or any of the other commercial 170 implementations (eg Day software, who contributed heavily to Jackrabbit).

For a Commercial implementation to work with Sakai it would need Level 2 170 support with locking and versioning from the optional feature set.