Rivet Logic Blogs

Tag: AWPr

The topic of Liferay and Alfresco integration continues to be popular among portal developers and what we’ve seen is that in the last year both products have matured in important ways to enable better integration. This evolution also opens the door for more possibilities. And as we all know, with more options there is more confusion. From my readings on the Liferay and Alfresco forums I observe that there are two main issues that puzzle people when they’re thinking about integrating Liferay and Alfresco:
What are the different possible ways for me to integrate the two products?
Which approach should I use?

To help answer these questions I thought it might be useful to list what the current options for integration are as well as a brief description of the architectural implications of each.

Note that the type of integration I’m referring to here is between Liferay Portal and Alfresco’s Document Management (DM) repository, and not the Web Content Management (WCM) repository.

Option #1: Using the Web script Container
With this approach you would basically deploy Alfresco’s Web script container into Liferay as a portlet application. Your Web scripts would be deployed along with the container and will be fully executed within the Liferay Portal context. What’s new here is that authentication between the Web scripts running in the container and the Alfresco repository will be taken care of automatically. This is nice since it alleviates the need to deploy the entire Alfresco WAR file into the portal as was the case with Alfresco versions prior to 3.2.

That said you should keep in mind that (for now) to accomplish this you would need to deploy the Alfresco Share WAR file in its entirety into the Liferay portal. It should be mentioned though that according to Will Abson’s blog post about the subject this is expected to change with the reduction of the needed WAR file’s footprint. Also, the portlet still needs some work to make it configurable from the Liferay Portal UI using portlet preferences — but I gather that this will be implemented eventually as well.

Option #2: Alfresco Web script Portlet rivet
Another option is Rivet Logic’s Alfresco Web script Portlet rivet (AWPr). This portlet is pretty much an Alfresco Web script proxy. With the help of a custom Alfresco authentication component known as STAr (Secure Token Authentication rivet), an AWPr portlet instance will use a series of Java HTTP Client calls to RESTfully and securely retrieve the rendered contents of a single Web script, proxy the contents so that all URLs are valid portal URLs (e.g. action URLs, serve resource URLs for downloads, etc.), and render the updated content in the portlet’s render phase.

AWPr has a very small footprint and thus can safely be used heavily on one Liferay portal page; meaning that a single portal page can have multiple instances of AWPr each configured to proxy a different Web script without much performance impact on the Liferay instance. Keep in mind that it is a proxy so the content is being transferred from Alfresco to Liferay and then from Liferay to the client browser, which might have some cost implications if bandwidth is not cheap and the Web script generated markup is large.

Options #3: Custom Portlet Development
For those of us who need to build their own custom portlets and need to have access to the Alfresco DM repository APIs from within their portlet code in order to perform certain ECMS functionality, there are a number of options.

CMIS
Recently, Alfresco, IBM, Microsoft, Documentum and others announced the submission of a new content management standard proposal called “CMIS” or “Content Management Interoperability Service” and on May 1st, 2010, the OASIS standards body approved CMIS v1.0 as an official OASIS Specification.

Alfresco has released a full implementation of CMIS v1.0, which includes support for both RESTful AtomPub and Web Services bindings. This basically allows Liferay portlet developers to use either one of those interfaces to communicate directly with the Alfresco repository (and any other content management system that supports the CMIS specification). More details on Alfresco’s CMIS support may be found at: http://wiki.alfresco.com/wiki/CMIS

RAAr
Another recently available option is presented by Rivet Logic’s Remote Alfresco API rivet (also referred to as RAAr). This API is a Java API that uses REST calls to communicate with a remote Alfresco repository. The advantage of this approach is that it provides all the pros of Alfresco’s Web services API but does not carry the burden of the SOAP stack — thus making it an attractive option for Java portlet developers.

RAAr is open source and is currently maintained by Rivet Logic Corporation. It provides most (if not all) of the Alfresco Foundation Service methods and can basically be used to do anything that the Alfresco web client can do.

More information about RAAr can be found at: http://wiki.rivetlogic.com/display/RAAr

Custom API
Even though it doesn’t really make much sense to do this I’m including this option just to be thorough. The idea here is that if you want to develop against Alfresoc’s REST API but want to abstract it using your own API you can do so. The problem with this approach is that depending on the problem you’re trying to solve you’ll eventually end up writing a CMIS API if you want to be platform independent (mostly) or RAAr if you want to access Alfresco’s service layer APIs remotely. So unless you have a legitimate reason to go down this road it’s most probably going to be better for you in the long run to stick with CMIS or RAAr.

This pretty much covers the options available for integrating Liferay with Alfresco’s DM repository. To know which options suites you best, you should weigh the features and drawbacks of each until you find a good fit, and with enough projects, making the right choice will start to become more obvious.

One of my favorite new features of Alfresco 3.2 is the concept of subsystems. Alfresco defines a subsystem as:

A configurable module responsible for a sub-part of Alfresco functionality. Typically, a subsystem wraps an optional functional area such as IMAP binding, or one with several alternative implementations, such as authentication.

In essence it’s like having mini child servers, each with its own Spring application context which makes configurability a lot more intuitive.

My first encounter with Alfresco’s subsystems was due to an AWPr jira issue that someone raised saying that STAr doesn’t work with Alfresco 3.2 because they “changed” the way authentication components are chained. To be honest my first reaction was “Oh no! More re-factoring!”. But then when I looked into how the Authentication Subsystem works it was clear that this new direction is better and allows for easier extensibility.

Remember how painful it was to chaining multiple LDAPs? Now it’s as simple as adding the following to your global properties file:

star-authentication-context.xml would basically contain the definition of the authentication component and authentication service with very minor differences from what it looked like in Alfresco 3.1. I documented the exact syntax on STAr’s wiki page.

The final step would be to modify alfresco-global.properties to add STAr to the authentication chain like so:

authentication.chain=alfrescoNtlm1:alfrescoNtlm,star1:star

It seems though that Alfresco 3.2r2 has a bug where it doesn’t pick up authentication subsystem entries from the extension folder on the shared classpath. So I had to release a new version of STAr (1.2.0) where the -context.xml file is in the STAr AMP and ultimately ends up inside alfresco.war. When Alfresco fixes this bug then STAr 1.1.0 will be sufficient.

To learn more about Alfresco’s subsystems and how to configure authentication components visit the following links:

The first approach works but in many cases requires that you develop custom Alfresco actions since the Web services API does not cover the full feature set of AFS (Alfresco Foundation Services).

The second approach provides us with more AFS coverage but has one restriction that is not easy to work with. It requires that all of Alfresco be deployed inside the portal as a portlet application. So if you needed to deploy JBoss Portal running an Alfresco Web script portlet that exposes the MySpaces Web script, the deployment would look like this:

The problem with this approach is that it introduces scalability constraints. Namely, if you need to scale the portal you are forced to scale Alfresco with it and vice versa.

For the Web services approach we have an alternative thanks to our Remote Alfresco API rivet (RAAr). With RAAr we are able to make use of Web frameworks like JBoss Seam backed by rich UI component libraries like RichFaces to develop JSR 168/286 portlets that expose most if not all of the AFS features using a Java-based API that uses RESTful communication to provide a secure and scalable interface to Alfresco. One example of a document library portlet that we created using this approach is shown below:

On the other hand, if you need to go with the Web script approach you’re pretty much out of luck unless you’re willing to go with the deployment architecture shown above. The fact that there was no single solution for this problem was all the motivation I needed to create AWPr (Alfresco Web Script Portlet rivet). With this portlet we will be able to have a better deployment architecture that could be represented by the following diagram:

Here the portal and the ECMS are in two separate tiers and can be managed or maintained as such. This not only allows for better flexibility when scaling becomes necessary, it also allows the portal to expose Web scripts that are hosted in different geographic locations.

To make this possible I leveraged a custom authentication component that we wrote called STAr (Secure Token Authentication rivet) that could be plugged into an Alfresco authentication chain. With this in place the portlet can carry the user credentials from the portal to Alfresco, authenticate the user in Alfresco and retrieve a ticket that can be used during all subsequent interactions between the end-user, the portlet and ultimately the Alfresco Web script itself.