This project has retired. For details please refer to its Attic page.
Apache Chemistry - OpenCMIS Server Framework
     
   
 

OpenCMIS Server Framework

The OpenCMIS Server Framework provides a server implementation of both CMIS bindings, AtomPub and Web Services, and maps them to Java interfaces. Requests and data from CMIS clients are converted and pushed to a repository connector. The connector then translates the CMIS calls into native repository calls.

Repository Connector Development

This is a brief description of the interfaces and classes a repository connector has to extend and implement. For interface details see the OpenCMIS Server Framework SPI JavaDoc.

Framework Entry Point

A repository connector has to extend the AbstractServiceFactory class. This class manages the objects that implement the CMIS service interface. There is only one active instance of this factory class per servlet context. The class name has to be set in the configuration file /WEB-INF/classes/repository.properties.

# set fully qualified class name
class=org.repository.ServicesFactory

The configuration file may contain more key-value pairs. They are passed to the init method of the AbstractServiceFactory object when the servlet context starts up.

For each request the getService method is called by the framework and a CallContext object is passed. This CallContext object contains data about the request, such as the used binding, the repository id, username and password. The getService method must return an object that implements the CmisService interface. This object is used by framework only for this one request and only in this thread. Therefore, the CmisService object need not to be thread-safe and and can hold request specific data. When the framework is ready to send a response and does not need the CmisService object anymore, it calls the close method. The repository connector can override this method to do repository specific clean ups (e.g. close a repository session, commit or rollback database transactions, remove temporary files, update caches, etc.).

It is up to the repository connector how these service objects are created and maintained. It is possible to create such an object for each request or keep an instance per thread in a ThreadLocal or manage service objects in a pool. If you reuse a service object make sure that it doesn't hold any state from previous requests.

Service Interface

The CmisService interface contains all operations of the CMIS specification and a few more. Most methods are named after the operations described in the CMIS specification. There are a few exceptions to that rule because the AtomPub binding doesn't always allow a one-to-one mapping. Those divergences are explained in the JavaDoc.

The methods take the same parameters as described in the CMIS specification. There are also a few exceptions that are explained in the JavaDoc.

It is recommended to extend the AbstractCmisService class instead of implementing the CmisService interface directly. AbstractCmisService contains several convenience methods and covers all AtomPub specifics in a generic way.

AtomPub Specifics

The AtomPub binding needs more object data than many of the operations return. Therefore a repository connector has to provide ObjectInfo objects through the getObjectInfo method. AbstractCmisService provides a generic implementation of getObjectInfo. If you don't notice any performance issue with the AtomPub binding, you don't have to bother with ObjectInfo objects.

If the generic assembly of ObjectInfo objects raises a problem, a repository connector can build them itself. AbstractCmisService provides a addObjectInfo method that takes and manages ObjectInfo objects. Which objects are required for which operation is documented in the JavaDoc.

Authentication Framework

Authentication information is transported to the service implementation via the CallContext object. The CallContext is basically a Map and can contain any kind of data. The OpenCMIS server fills it by default with a username and a password from either HTTP basic authentication for the AtomPub binding or WS-Security (UsernameToken) for the Web Services binding.

Other authentication methods can be plugged in if needed. Here is how this works for the two CMIS bindings.

AtomPub authentication

For the AtomPub binding a new class implementing the interface org.apache.chemistry.opencmis.server.impl.atompub.CallContextHandler has to be created. It gets the HttpServletRequest object of the current request and returns key-value pairs that are added to the CallContext. See the JavaDoc for details.

The new CallContext handler can be activated by changing the servlet init parameter callContextHandler in /WEB-INF/web.xml.

    <init-param>
      <param-name>callContextHandler</param-name>
      <param-value>org.example.opencmis.MyCallContextHandler</param-value>
    </init-param>

Web Services authentication

For the Web Services binding a new SOAPHandler class has to be created and registered in /WEB-INF/sun-jaxws.xml.

The handleMessage method should look like this:

    public boolean handleMessage(SOAPMessageContext context) {
      Boolean outboundProperty = (Boolean)
            context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
      if (outboundProperty.booleanValue()) {
        // we are only looking at inbound messages
        return true;
      }
    
      // do whatever you have to do here
      String user = ...
      String secret = ...
  
      // set up key-value pairs for the CallContext
      Map<String, String> callContextMap = new HashMap<String, String>();
      callContextMap.put("org.example.opencmis.user", user);
      callContextMap.put("org.example.opencmis.secret", secret);
    
      // add key-value pairs the SOAP message context
      context.put(AbstractService.CALL_CONTEXT_MAP, callContextMap);
      context.setScope(AbstractService.CALL_CONTEXT_MAP, Scope.APPLICATION);
    
      return true;
    }

Repository Connector Deployment

The OpenCMIS build process creates a WAR file in /chemistry-opencmis-server/chemistry-opencmis-server/target. This WAR file should be used as a template. It can be deployed as it is but doesn't do anything.

In order to use your connector, copy your compiled connector code into this WAR file and overwrite /WEB-INF/classes/repository.properties.

Have a look at the OpenCMIS FileShare Repository test repository code and pom.xml. It's a simple example of a repository connector.