Developing Portlets using JSF, Ajax, and Seam (Part 1 of 3)

If you are just starting to look at using a portal solution, or you want to learn how easy it is to integrate a new or existing JSF application into a portal environment, then this article is for you.

Portals have gained a lot of ground over the past few years, both in the enterprise and with the new enhancements of the portlet 2.0 (JSR 286) specification. The new 2.0 portlets allow you many freedoms in aggregating different applications and presenting them in different windows on one page. And of course, you get authentication, sophisticated personalization features, and better ways of handling AJAX out of the box.

With the JSR 301 portlet bridge specification, we now have a standard way of running JSF applications as both 1.0 and 2.0 portlets. The portlet bridge handles the portal Action/Render paradigm to properly handle the JSF lifecycle. While this tutorial is mainly to show you how easy it is to configure and develop a JSF portlet, I will also be revealing the new JBoss Portlet Container 2.0 and some of it’s cool new features.

Currently, JBoss Portlet Bridge is the only implementation of the JSR 301 spec that allows you to run any combination of JSF, RichFaces, and Seam. The Maven configuration for your project is setup to download JBoss AS and JBoss Portlet Container 2.0 packaged together. If you want to download them seperately, you can find them here. Otherwise, allow Maven a few minutes to download the proper files during the next steps.

Note - This portlet can also be run in the current 2.6.5.SP1 version of JBoss Portal. I am using the JBoss Portlet Container 2.0 for this article, but the bridge works in either. You can read how to configure to run in any version of JBoss Portal here.

The following Maven archetype is a simple way to get up and running quickly with a starter (or template) project. Once you run this command, you will have everything you need to develop and follow this guide.

Now navigate to the directory where you created your new project. If you use the example above, it would be the "myprojectname" directory. Take a look around, browse through the files that were just created. You will see the basic Maven folder structure with source code for this tutorial. Now would also be a good time to fire up your favorite IDE and import this Maven project.

Portlet Bridge Configuration Requirements

From here, development will be much like developing any other JSF application in the servlet world. The only differences will be dealing with things like Single Sign-On, the portletContext and accessing variables that are needed for things like namespacing, and window modes in your portlet like 'Help' and 'Edit' modes. I'm not going to get into the extreme details of the portlet world, but I will give you the information needed to do basic development. If you need more information about portlets please read the JSR 168 or JSR 286 specifications.

The cool thing about the JBoss Portlet Bridge is that, it’s not a portlet. It’s simply a mediator between the portlet and JSF worlds. Your JSF application is the portlet. Your WEB-INF directory will contain 3 or 4 extra xml files along with the bridge jars, but everything else stays the same as the servlet version of your application. The only differences are in the following configuration files:

The above settings are already applied in the Maven archetype which you just set up. So now it's time to compile the project and deploy it to JBoss Portal.

Running the demo application

Compile your new project and deploy in 2 steps:

Step 1:mvn install cargo:start -Premote-portal -Dpc20

This command will take a few minutes to download the server+portal bundle so please wait until you see the following before taking the next step:

*Note - you will also see a PortletException just before the server starts. This is normal and is part of the Portlet Container 2.0 demo's FailDuringInitPortlet.

Next open a second terminal window, navigate to the JSF portlet project root and run:

Step 2:mvn cargo:deploy -Premote-portal -Dpc20

The command line parameters instruct cargo on where the JBoss+Portal bundle is located and what version of portal you are running. You can also run this example on the latest version of the JSR 168-compliant JBoss Portal 2.6.5.SP1. For more information and Maven commands see section the JBoss Portlet Bridge documentation found here. To view the deployed JSF portlet visit: http://localhost:8080/simple-portal/demo/jsr-301.jsp

JSF Portlet Development

Now, let's look at a few things that tie portlet and JSF development together.

Viewing your portlet as a normal webapp

The portlet bridge is transparent when viewing your application as a servlet-side web app. As a portlet developer, it's nice to have a sanity check every once and a while to ensure that what you're developing is not blowing up because you're running it in a portal environment. To view this demo application, or any application deployed with the bridge, you can visit http://localhost:8080/JSFRIPortlet/home.jsf

Namespacing

The bridge handles the namespacing combinations of JSF in the portal environment. In situations where you need to use the id of an element in your JSF/xhtml markup, you would normally see something like 'form1:myBtn' in the rendered markup. But now with the bridge namespacing you will see something similar to: jbpns_2fdefault_2fNews_2fStories_2fStoryTemplateWindow12snpbj:_viewRoot:form1:myBtn

To overcome this, you can use the following expression in your Facelets page to prepend the namespace to your javascript code:document.getElementById('#{facesContext.externalContext.response.namespace}the_rest_of_JSF_ID');

Please note that since this uses the portletResponse, once you try to view this page on the servlet application side you will get an exception. To avoid this, you need to check for the type of response in your backing bean and assign a new "safe" namespace variable for the UI.

preserveActionParams

When preserveActionParams is set to TRUE in your web.xml, the bridge must maintain any request parameters assigned during the portlet's action request. The request parameters are maintained in the "bridge request scope". When this attribute isn't present or is FALSE the action's request parameters are only maintained for the duration of the portlet request scope.

Using something like #{request.yourParam} in your Facelets page will utilize this setting.

Excluding Attributes from the Bridge Request Scope

When your application uses request attributes on a per request basis and you do not want that particular attribute to be managed in the extended bridge request scope, you must use the following configuration in your faces-config.xml. Below you will see that any attribute namespaced as foo.bar or any attribute beginning with foo.baz(wildcard) will be excluded from the bridge request scope and only be used per that application's request:

Or you can use the javax.portlet.faces.annotation.ExcludeFromManagedRequestScope annotation to accomplish the same thing by annotating the object class that you don't want to be included in the request.

Conclusion

As you can see, the JSR 301 specification not only makes it simple to set up an existing JSF web application as a portlet, but also gives you (the developer) a way to manage and handle the differences between JSF and portlets. With that said, the spec is still under heavy review and revisioning. As of the writing of this article, Early Draft Review 3 is the latest public version but there have already been many advancements on top of this revision inside the JSR 301 Expert Group. One of the larger enhancements to the bridge is portlet-mode navigation and state which will be implemented in the the next version (Beta 4) of the JBoss Portlet Bridge.

To find out more about the project, compatible versions that the bridge supports, or to participate in the community forums please visit our project page and blog.

C:\>mvn install cargo:start -Premote-portal -Dpc20[INFO] Scanning for projects...[INFO] Searching repository for plugin with prefix: 'cargo'.[INFO] ------------------------------------------------------------------------[ERROR] BUILD ERROR[INFO] ------------------------------------------------------------------------[INFO] The plugin 'org.apache.maven.plugins:maven-cargo-plugin' does not exist or no valid version could be found