Enterprise Integration Zone is brought to you in partnership with:

Bilgin Ibryam is a software engineer with Master's degree in Computer Science and currently working for Red Hat in London. He is also the author of "Instant Apache Camel Message Routing" book, an open source enthusiast, Apache OFBiz, and Apache Camel committer. In his spare time, he enjoys contributing to open source projects and blogging at ofbizian.com. Bilgin is a DZone MVB and is not an employee of DZone and has posted 23 posts at DZone. You can read more from them at their website. View Full User Profile

Content Migration with Camel-CMIS

04.28.2013
| 2396 views |
  • submit to reddit

Some time ago(actually quite a long time ago now) I was playing with CMIS using Apache Chemistry, Camel, Talend… and created a camel-cmis connector. And recently this component reached camel trunk, so here are some example how it can be used.

Motivation
Content Management Interoperability Services (CMIS) is an open standard that defines an abstraction layer for accessing diverse document management systems and repositories using web protocols. Administered by OASIS and backed by Adobe, Alfresco, HP, IBM, Microsoft, Oracle and many more, it defines data model and query language for accessing content repositories in a language agnostic way.
If you are already familiar with Java Content Repository API (JCR), CMIS is kind of similar. JCR specifies an API while CMIS specifies protocol bindings. Much like the Servlet API in Java and the HTTP protocol are complementary this is also the case for JCR and CMIS.

Apache Chemistry project provides open source implementations of the CMIS specification. It has implementations in Java, Python, PHP and .Net.

CAMEL-CMIS
The component uses OpenCMIS (Apache Chemistry's Java implementation) and contains a producer and a consumer. The producer can be used in two ways:

Create nodes (documents with content data, folders and other node types) from Camel messages. In the example below, the route will copy all of the files from the local file system into a demo directory in Alfresco demo cmis server using the file name as node name.
public class CamelCmisFileUploader extends RouteBuilder {

    public void configure() {
        from("file:src/demo?noop=true")
                .process(new Processor() {
                    public void process(Exchange exchange) throws Exception {
                        exchange.getIn().getHeaders().put(PropertyIds.CONTENT_STREAM_MIME_TYPE, "text/plain; charset=UTF-8");
                        exchange.getIn().getHeaders().put(PropertyIds.NAME, exchange.getIn().getHeader(Exchange.FILE_NAME));
                        exchange.getIn().getHeaders().put(CamelCMISConstants.CMIS_FOLDER_PATH, "/demo");
                    }
                })
                .to("cmis://http://cmis.alfresco.com/cmisatom?repositoryId=371554cd-ac06-40ba-98b8-e6b60275cca7&username={{username}}&password={{password}}");
    }
}
Query the content repository using cmis query language. The result of the query is a list in the body of the message. The route below will retrieve all documents with name containing the word 'camel', split them and store each one into the local file system, using the document name as the file name.
public class CamelCmisQueryProducer extends RouteBuilder {

    public void configure() {
        from("timer://foo?repeatCount=1")
                .setBody(constant("SELECT * FROM cmis:document WHERE cmis:name LIKE '%camel%'"))
                .to("cmis://http://cmis.demo.nuxeo.org/nuxeo/atom/cmis&username={{username}}&password={{password}}&queryMode=true&readContent=true")
                .split(body())
                .process(new Processor() {
                    public void process(Exchange exchange) throws Exception {
                        Map<String, Object> body = (Map<String, Object>)exchange.getIn().getBody();
                        exchange.getIn().getHeaders().put(Exchange.FILE_NAME, body.get(PropertyIds.NAME));
                        exchange.getIn().setBody(body.get(CamelCMISConstants.CAMEL_CMIS_CONTENT_STREAM));
                    }
                })
                .to("file:src/demo");
    }
}
The consumer accepts a cmis query through the options. If the query string is not provided, the consumer will iterate the complete content tree recursively starting from the root node. Using this option you can replicate the complete cmis structure into another cmis repository (as in the following example, which tries to copy the complete alfresco repo into nuxeo one - don't do this at home) or back it up into the local file system. Notice that to retrieve the actual content data for document nodes, you have to set the readContent option additionally.
public class CamelCmisRepositoryReplication extends RouteBuilder {

    public void configure() {
        from("cmis://http://cmis.alfresco.com/cmisatom?repositoryId=371554cd-ac06-40ba-98b8-e6b60275cca7&username={{username}}&password={{password}}&readContent=true")
        .to("cmis://http://cmis.demo.nuxeo.org/nuxeo/atom/cmis?username={{username}}&password={{password}}");
    }
}
If the target repository doesn't support support CMIS, but JCR try replacing the endpoint with the camel-jcr component, or choose something else from one of the 120 existing Camel components.

Published at DZone with permission of Bilgin Ibryam, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Hardik Desai replied on Thu, 2014/01/30 - 12:14pm

Hi Bilgin,

I used the FileUploader as shown below:

public class CamelCmisFileUploader extends RouteBuilder {
@Overridepublic void configure() throws Exception {from("file://path/metamodel?noop=true&idempotent=false").process(new Processor() {public void process(Exchange exchange) throws Exception {exchange.getIn().getHeaders().put(PropertyIds.CONTENT_STREAM_MIME_TYPE, "application/json");exchange.getIn().getHeaders().put(PropertyIds.NAME, exchange.getIn().getHeader(Exchange.FILE_NAME));}}).to("cmis://http://localhost:8080/chemistry-opencmis-server-jcr/atom/metamodel?username=admin&password=admin");}}


Although the files are getting copied, but I am getting the following exception on every file:

org.apache.chemistry.opencmis.commons.exceptions.CmisStorageException: Unable to perform versioning operation on non versionable node: /AchControlTableRecord.jsonat org.apache.chemistry.opencmis.client.bindings.spi.atompub.AbstractAtomPubService.convertStatusCode(AbstractAtomPubService.java:485)at org.apache.chemistry.opencmis.client.bindings.spi.atompub.AbstractAtomPubService.post(AbstractAtomPubService.java:629)at org.apache.chemistry.opencmis.client.bindings.spi.atompub.ObjectServiceImpl.createDocument(ObjectServiceImpl.java:119)at org.apache.chemistry.opencmis.client.runtime.SessionImpl.createDocument(SessionImpl.java:751)at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:95)at org.apache.chemistry.opencmis.client.runtime.FolderImpl.createDocument(FolderImpl.java:469)at org.apache.camel.component.cmis.CMISProducer.storeDocument(CMISProducer.java:130)at org.apache.camel.component.cmis.CMISProducer.createNode(CMISProducer.java:69)at org.apache.camel.component.cmis.CMISProducer.process(CMISProducer.java:51)at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)


Can you please help? Thanks!

Hardik

Bilgin Ibryam replied on Fri, 2014/01/31 - 6:48pm

 The best place to get an answer for this question is Camel users mailing list.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.