We live in a mobile world, it’s true. Perhaps more importantly, we live in a Bring Your Own Device (BYOD) world where employees increasingly use their personal mobile devices to perform work tasks. Despite the inherent security risks, this is an amazing opportunity for productivity. We need to be able to build applications that are convenient for these mobile users but flexible, adaptable, and easy to maintain.

The Nuxeo Solutions Architect team has an example application called the Case Management Platform that we use quite often to demonstrate the kind of application you can build with the Nuxeo Platform. It’s designed to process claims for a fictitious insurance company.

But before we dive in, read about the Future of Claims Management here or learn more about our solutions for content management for insurance companies >

It contains, among other things, insurance claim documents:

Insurance Claim Information

It also contains a claim summary report that’s accessible via a button for any claim:

Button to generate claim report

The report depends on the Nuxeo Template Rendering add-on and uses an OpenDocument text file for template to produce a PDF report like this:

Nuxeo case report

As you can see, this report is normally accessed via the Nuxeo Application. Wouldn’t it be nice if an insurance agent on the road could access a list of their open claims and get a copy of this report? Maybe even on a tablet or phone? Maybe something like this?

Nuxeo for Case Management insurance - example screenshot

What you see above is a simple single-page Web application running on Apache. It talks to the Case Management Platform to get a list of claims, and provides a download link for the report of each claim. The download is NOT a static file. It is a link to the exact same dynamically generated report that’s available in the Case Management Platform.

How did I do that?

Building Blocks

In a recent blog Nuxeo CTO Thierry Delprat mentioned the following:

In addition to that, CMIS has a community; there are several JavaScript libraries built to handle CMIS communication for Web applications.

All of the building blocks are here to quickly and easily build a mobile Web application to access these “Reports on the Road”. As a bonus, since the application shown in this blog uses CMIS, it is not tied to any specific content repository.

Renditions to the Rescue

The first thing to do is expose the claim summary report as a rendition. The report is already configured to be an automation operation (thanks to the Nuxeo Template Rendering addon), so this is just a matter of creating a new automation chain run the report: - Document.Pop - TemplateProcessor.Render: save: "false" store: "false" templateName: Claim Report Important: when a rendition is based on an automation chain, the DefaultAutomationRenditionProvider expects to provide the chain with a blob as input. Furthermore, the context document has been pushed. In my case there was no blob (I will explain this in a moment). I actually wanted the context document and not any blob, because this report uses the metadata from the InsuranceClaim document and not a binary. So the first operation in this chain, Document.Pop, restores the document that I wanted to use. With the new automation chain in place, it’s time to declare it as a rendition. This requires a simple XML contribution:

<extension target="org.nuxeo.ecm.platform.rendition.service.RenditionService" point="renditionDefinitions">
    <renditionDefinition enable="true" name="claimReport">
        <label>Claim Report</label>
        <contentType>application/pdf</contentType>
        <operationChain>Rendition-GenerateClaimReport</operationChain>
        <allowEmptyBlob>true</allowEmptyBlob>
    </renditionDefinition>
</extension>

Important: as I mentioned above, renditions often involve converting one blob type to another (e.g. a Word document to PDF). But this claim report creates a PDF from document metadata. So the allowEmptyBlob setting is critical here because there is no input binary.

Important: in order for a rendition to be accessible via CMIS, it must declare the contentType setting.

And that’s it! The rendition is now available to any CMIS client.

CMIS to the Rescue

I knew I wanted to build a simple Web application to expose my reports to mobile users. It’s true that Nuxeo provides all the API’s I could ever need and a JavaScript client to build a Web application with the full capability to access content in a Nuxeo repository (and much much more!). But I also wanted to build a client that was flexible and agnostic (and let’s be honest, I was tasked with learning about CMIS! :) ).

I soon discovered that CMIS 1.1 understands the concept of a rendition and Nuxeo 5.9.4 added the ability to expose Nuxeo renditions as CMIS renditions.

On the other hand, I knew that I did NOT want to build my own JavaScript CMIS client. Thankfully several already exist and I settled on one called CmisJS. One word of caution: if you are like me, you are not a Web developer by trade. CmisJS is implemented as a Node.js library (it runs in the browser as well), so it uses asynchronous JavaScript. To use it you’ll have to get used to callback-style programming. Also CmisJS has a dependency on an ajax client called SuperAgent.

So I set about building a Web application that would use CMIS to get the claim reports.

Time to Get to Work!

With all these tools in hand, what’s needed to access the claim reports from a mobile device? To be blunt, this application was absurdly easy to build. This is a summary of all the necessary CMIS calls:

session = cmis.createSession()
session.setCredentials()
session.loadRepositories()
session.query()
session.getContentStreamURL()

The session object comes from Cmis.JS and it’s the root of any CMIS access.

The setCredentials() function is self-explanatory.

The loadRepositories() function is what actually performs the connection to Nuxeo.

The query() function is used to fetch the metadata to display in the application, as well as the document id’s. Note that the results are filtered to only show claims for the current user; here is the query:

var query = "";
query = query + "SELECT ";
query = query + "   cmis:objectId, ";
query = query + "   incl:incident_id, ";
query = query + "   pein:first_name, ";
query = query + "   pein:last_name, ";
query = query + "   nuxeo:lifecycleState ";
query = query + "FROM ";
query = query + "   InsuranceClaim ";
query = query + "WHERE ";
query = query + "cmis:createdBy = '" + cmisConfig.userName + "'";

With each document id in hand, the getContentStreamURL() function provides a link to the rendition. Here is the code:

var reportURL = session.getContentStreamURL(docId, true, {
    streamId: "nuxeo:rendition:claimReport"
});

The key point here is the streamId. It has the format “nuxeo:rendition:<yourRenditionName”; the rendition name is specified in the contribution to the “renditionDefinitions” extension point. Here is an example URL:

http://localhost:8080/nuxeo/json/cmis/default/root?succinct=true&**streamId=nuxeo%3Arendition%3AclaimReport**&cmisselector=content&objectId=24dcbae2-f843-4eab-8b80-9d54624ee6e4&download=attachment

Of course I had to build the page to provide the links, but that’s just an exercise in HTML, CSS, and a little JavaScript. You can find the full source for this project here. Just to be clear this is not a working example in the sense that it is designed to talk to a specific Nuxeo application. I am providing the source code for study and review.

An interesting side task was that I needed to figure out how to download the PDF report from a single-page Web application. In other words figure out how to download a file, with authentication, and save it to the user’s computer from Javascript. I blogged about that previously here.

Summary

CMIS renditions offer a really convenient way to access dynamic content in a Nuxeo repository, even renditions based on automation. Given that CMIS is an industry-wide specification, it enjoys great support even in terms of development libraries. With a small amount of work it’s possible to build simple, easy to use Web applications suitable for all those BYOD-wielding employees out there anxious to be more productive.

Just remember these important tips:

  • Renditions based on automation will have the document pushed onto the stack. Use Document.pop in the automation chain to access the document.
  • If your rendition does not rely on a blob, make sure the rendition contribution sets “allowEmptyBlob” to “true”.
  • To access a rendition via CMIS, make sure that the rendition contribution contains a “contentType”.