Since Alfresco 3.2r the ProxyPortlet support in Alfresco Share has allowed developers to easily embed specific bits of Share functionality into a portal such as Liferay, using only a small amount of XML configuration to wire in existing web scripts.
This support has been substantially improved in version 3.4 of Alfresco, in order to allow the entire Share Document Library page to be embedded within a portal. Unfortunately the changes mean that the steps in Luis’s original tutorial no longer work in the latest version.
As one of the features we demonstrated today at our Madrid event was the Doclib portlet, I managed to get five minutes to get the original web script-backed method working too.
Since the CMIS repository browsing web scripts used in Luis’s example are no longer shipped with Share, I used my own Hello World dashlet from share-extras as a starting point instead. The web script is basic, but demonstrates displaying a simple greeting to the user including their user name.
The following steps should work using a recent version of Alfresco 3.4 and Liferay 5.2.3 running as the portal, provided that the two components are first set up as per the Installing and Configuring instructions for the Doclib Portlet.
Once you’ve set everything up, the first thing to do is to add the web script files to the instance of Share that you have already deployed to Liferay. Since you should already have created some directories in Liferay’s tomcat-x.x.x/shared/classes directory to define your share-config-custom.xml, the easiest thing is to create a new directory named site-webscripts within the existing tomcat-x.x.x/shared/classes/alfresco/web-extension and place the following files in it.
org/alfresco/test/hello-world.get.desc.xml
<webscript> <shortname>Hello World</shortname> <description>Displays Hello World text to the user</description> <authentication>none</authentication> <url>/test/hello-world</url> </webscript>
org/alfresco/test/hello-world.get.html.ftl
<html> <head> <title>${msg("header")}</title> </head> <body> ${msg("label.hello", user.id)} </body> </html>
org/alfresco/test/hello-world.get.properties
header=Hello World! label.hello=Hello {0}
With those files added, you’ve successfully defined the web script that we’ll wire into Share in the next section.
Now although the web script itself will be automatically picked up by Share at load-time, some additional config is also needed in web.xml for the ProxyPortlet to work in version 3.4.
The following lines, which define a custom servlet and servlet mapping which will be invoked by the ProxyPortlet, should be placed in the web.xml file belonging to the Share instance which has been deployed in Liferay. You should find the path to this will be something like <LIFERAY_HOME>/tomcat-6.0.18/webapps/share/WEB-INF web.xml (if you have not already started Liferay you will need to do so to force it to deploy share.war and create this structure).
<servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>com.liferay.portal.kernel.servlet.PortletServlet</servlet-class> <init-param> <param-name>portlet-class</param-name> <param-value>org.alfresco.web.portlet.ProxyPortlet</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet> <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/HelloWorld/*</url-pattern> </servlet-mapping>
You can place these two definitions anywhere within the top-level <web-app> element, but for consistency I always try to add them next to the existing <servlet> and <servlet-mapping> definitions.
Now you’ve done all you need to do to configure the scripts, we can move onto configuring the matching portlet definition which will be picked up by Liferay.
In the same WEB-INF directory where you modified web.xml you should find a file named portlet.xml, to which we add our new definition.
<portlet> <description>Hello World</description> <portlet-name>HelloWorld</portlet-name> <portlet-class>org.alfresco.web.portlet.ProxyPortlet</portlet-class> <init-param> <name>viewScriptUrl</name> <value>/page/test/hello-world</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW</portlet-mode> </supports> <portlet-info> <title>Hello World</title> <short-title>Hello World</short-title> </portlet-info> <security-role-ref> <role-name>administrator</role-name> </security-role-ref> <security-role-ref> <role-name>guest</role-name> </security-role-ref> <security-role-ref> <role-name>power-user</role-name> </security-role-ref> <security-role-ref> <role-name>user</role-name> </security-role-ref> </portlet>
Add this right after the existing <portlet> definitions (which if you look at further it should be obvious define the three Doclib portlets) and save your changes.
Getting these details right is crucial if you’re deploying your own web scripts, so a couple of notes on this are probably useful.
- The contents of the <portlet-name> element must match the name of the servlet mapping you have defined in web.xml
- The viewScriptUrl parameter must match the URL of your web script, with a prefix of /page added to the beginning (note that in 3.2r the web app context path was also required in the URL, but this now causes an error if supplied)
Lastly you should add the portlet to the two Liferay-specific configuration files in WEB-INF to ensure that authentication is handled correctly and also that the portal appears in the correct category in Liferay’s Applications menu.
In liferay-portlet.xml add the following definition after the existing <portlet> elements
<portlet> <portlet-name>HelloWorld</portlet-name> <user-principal-strategy>screenName</user-principal-strategy> </portlet>
In liferay-display.xml, add the following within the existing <category> element – it should be obvious that this is adding your portlet to the ‘Alfresco’ category.
<portlet id="HelloWorld"></portlet>
You’ll need to restart Liferay to get it to pick up the new portlet, and for Share in turn to load the additional web script. Once it’s finished loading you should be able to follow the configuration steps in the Doclib Portlet guide to walk you through adding it to a page.
The example is basic, but shows how you can add a web script as a portlet, with a small amount of personalisation based on the identify of the user.
It’s possible to add more complex web scripts, for example to load data from the Alfresco repository or other back-end data sources, but as Luis points out you should be careful how you render any hyperlinks within your scripts, to ensure that they are portal-safe.
To make sure that your URLs are correctly generated, please use the “scripturl()” function in your Freemarker templates to wrap them:
<a href=”${scripturl(url.serviceContext + “/sample/cmis/repo”, false)}”>CMIS Repository</a>
You can download the web script files used in this example in JAR format, which you can extract using any unzip program into the directories specified above (or even easier – simply drop the JAR file itself into Liferay’s tomcat-x.x.x/shared/lib folder).
Good post thanks !
Could you please detail the exact role of the “ProxyPortlet support in Alfresco Share” ? Does it manage some kind of URL rewriting or the authentication or any other features ?
Also, could you confirm the webscript can be located in the Alfresco DM repository ? My question is about proxing actually : if the portal is a proxy for Alfresco Share, and Alfresco Share is a proxy for DM…then the chaining becomes complexe…
Enguerrand
Hi Enguerrand, the ProxyPortlet class provides the portlet implementation that is used to ‘proxy’ the web script request over to Alfresco. If you want more details on how it works, I’d suggest taking a look at the source code itself – see http://www.springsource.org/extensions/se-surf.
I believe you can use a similar technique to embed repository web scripts in Liferay, but as the focus is now on using Share to render UI components where possible, pulling data from the repository (or other sources) when required as you say, the three-tier approach fits better with that. In any case since the ProxyPortlet ‘redirection’ is handled internally, it’s likely you would only have one external call being made, so the benefits should outweigh the small additional overhead.
Hi Will –
Will this same procedure work with Liferay 6? Is there any conflict with LR’s doc lib portlet? I suspect there is some naming conflicts between Alfresco and LR doc lib. We are working with A 3.4 and LR 6 both enterprise versions.
Thanks
Shari
Hi Shari, your comment is a little off-topic as technically this topic is not about the Doclib Portlet, but nonetheless you can see a summary of the issues with Liferay 6 here – http://issues.alfresco.com/jira/browse/ALF-5770.