BT

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

Posted by Wesley Hales on Aug 19, 2008 |

In Part 1, we saw the basics of running a JSF portlet. We looked at project setup, 3 basic xml configurations that are needed, and common development how-tos that most JSF Portlet developers will eventually face. Now I will show you how to enhance your JSF portlet with AJAX via the RichFaces component library.

Project Setup

Development Tools:

To follow along with this guide, download the latest version of Maven. (I am using 2.0.9)
Install Maven 2.0.9+
Set the Maven binaries on your path

Server and binaries used in examples:
JBoss Portal 2.7 Beta1
JBoss Portlet Bridge Beta3

In the previous article, I explained our use of Maven archetypes and how the project you are about to setup is automatically deployed to JBoss Application Server running JBoss Portal via Maven. The first few parts of this article are purposely identical to the previous one for ease of use. The only changes are in the actual project name -- all of the Maven commands remain the same. Once your RichFaces project is setup, you will have a solid reference and a testing ground to try out some of the code samples below.

Now it's time to generate the RichFaces project, examine the source code, and briefly step through the configuration. Finally, we will run the demo and look at some real world development tasks.

Open a terminal and run:

mvn archetype:generate
 -DarchetypeGroupId=org.jboss.portletbridge.archetypes
 -DarchetypeArtifactId=richfaces-basic -DarchetypeVersion=1.0.0.B3
 -DgroupId=org.my.project -DartifactId=richfacesproject
 -DarchetypeRepository=http://repository.jboss.org/maven2/
 -Dversion=1.0.0.B3

Navigate to the directory where you created your new project. If you use the example above, it would be the "richfacesproject" 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 start your favorite IDE and import this Maven project.

Configuration

There are minimal XML changes that must be made to immediately begin using any component from the RichFaces library. These settings are an extension to the original configuration mentioned in Part 1 so I will only review the JSF-related configuration for JBoss Portlet Bridge.

The following settings will vary based on your individual needs. To keep this article focused on AJAX portlet development I will only explain how these options relate to your portlet. For more information see this section of the RichFaces documentation.

web.xml

--------------

The scripts and CSS styles that are needed to display the RichFaces components can be controlled here. For JBoss Portal, we can turn off the loading of the styles and scripts so that they are only loaded once in the portal page head:

 

<context-param>
     <param-name>org.richfaces.LoadStyleStrategy</param-name>
     <param-value>NONE</param-value>
 </context-param>
 <context-param>
     <param-name>org.richfaces.LoadScriptStrategy</param-name>
     <param-value>NONE</param-value>
 </context-param>
 <context-param>
     <param-name>org.ajax4jsf.RESOURCE_URI_PREFIX</param-name>
     <param-value>rfRes</param-value>
 </context-param>

 <filter>
     <display-name>Ajax4jsf Filter</display-name>
     <filter-name>ajax4jsf</filter-name>
     <filter-class>org.ajax4jsf.Filter</filter-class>
 </filter>

 <filter-mapping>
     <filter-name>ajax4jsf</filter-name>
     <servlet-name>FacesServlet</servlet-name>
     <dispatcher>FORWARD</dispatcher>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>INCLUDE</dispatcher>
 </filter-mapping>

jboss-portlet.xml

--------------

This is where you specify what is loaded in the portal page head. As you can see, "rfRes" is what we specified as the RESOURCE_URI_PREFIX in the web.xml. The next step is to insert our servlet_path/RESOURCE_URI_PREFIX to access the RichFaces resources that are served from the classpath.

These are the 3 files that are needed to properly display and enable the RichFaces component suite:

<portlet>
     <portlet-name>ajaxPortlet</portlet-name>
     <header-content>
         <script src="/faces/rfRes/org/ajax4jsf/framework.pack.js" type="text/javascript"></script>
         <script src="/faces/rfRes/org/richfaces/ui.pack.js" type="text/javascript"></script>
         <link rel="stylesheet" type="text/css" href="/faces/rfRes/org/richfaces/skin.xcss"/>
     </header-content>
 </portlet>

Running the demo application

Now we will fire up the server and deploy your RichFaces portlet with 2 simple commands. One thing I will explain before we get started is the difference in JBoss Portal installations between this article and the previous one. In the last article we deployed to a JBoss App Server running the lightweight Portlet Container 2.0 demo. Since that article was published, we have released JBoss Portal 2.7 as a beta. This combines the old JSR-168 implementation of JBoss Portal with the new Portlet 2.0 implementation, giving us the ability to run 1.0 and 2.0 portlets in the standard JBoss Portal project. So if keeping track of what version you should be using seems confusing, it's not. Just keep in mind that JBoss Portal 2.7 is the ultimate combination of everything we have to offer and versions 2.6.x are the supported stable releases that only support JSR-168 (portlet 1.0). 

For more info on deploying this demo portlet to any version of JBoss Portal (beta or stable) read here.

Step 1: Download and start the server.

Download the bundled JBoss App Server with JBoss Portal 2.7 Beta1 from http://downloads.sourceforge.net/jboss/jboss-portal-2.7.0.B1-bundled.zip

Next, make sure you replace "path_to_bundle_zip" below with the absolute path of the JBoss Portal 2.7 bundle and run:

mvn install cargo:start -Plocal-portal -DJBOSS_ZIP_HOME=/path_to_bundle_zip/jboss-
portal-2.7.0.B1-bundled.zip -DJBOSS_HOME_DIR=jboss-portal-2.7.0.B1-
bundled/jboss-portal-2.7.0.B1

This command may seem a bit lengthy, but it gives you the opportunity to package any modified compatible version of JBoss App Server and JBoss Portal.

Once you see the output below, you can proceed to the next step:

Step 2: Deploy the demo application

Now open a second terminal window and navigate to your "richfacesproject" root and run:

  mvn cargo:deploy -Plocal-portal -DJBOSS_ZIP_HOME=/path_to_bundle_zip/jboss-
portal-2.7.0.B1-bundled.zip -DJBOSS_HOME_DIR=jboss-portal-2.7.0.B1-bundled/jboss-
portal-2.7.0.B1

Don't forget to replace "path_to_bundle_zip" with the correct path.

Now you can access your RichFaces demo portlet at http://localhost:8080/portal/portal/default/RichFacesEchoPortlet.

RichFaces Portlet Development

When making an AJAX request from a portlet, it's important to know the differences between the portlet and servlet sessions. For instance, when a user makes an AJAX request inside of the portlet, it happens using a raw HTTP session and the call does not have access to the objects that are in the portal session. For this problem we have implemented a method that will allow us access to the Portlet session attributes. They are scoped using the window id value -- for instance, if the Portlet puts the value 'YourObject' in the Portlet session, it will be stored as 'javax.portlet.p.XYZ?YourObject' where XYZ is the window id.

To access the windowID or scopeID from the UI you may use the following:

#{facesContext.externalContext.sessionMap['org.jboss.portletbridge.WINDOW_ID_RETRIVER'].windowID}
 #{facesContext.externalContext.sessionMap['org.jboss.portletbridge.WINDOW_ID_RETRIVER'].scopeId}

As you can see, facesContext.externalContext.sessionMap points to the portlet-scoped session objects. Why might you need to use these values? To name a couple of cases:

  • When you need authentication data from the portal session during an AJAX request
  • Dynamic resource generation (images, scripts, etc...)

Other Examples

The entire RichFaces library is available in a working demo and the source code is available for download here. This project is extremely useful if you are unsure of your component configuration or if you think it isn't working in the portal environment. The only component that isn't available is the file upload component. It is scheduled to be available in the next portlet bridge release sometime early September.

As always, feedback on the forums is extremely useful and welcome. For more information about the JBoss Portlet Bridge project visit the project page, documentation, or wiki.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Excellent series so far! by John Haselden

Thanks Wesley, this has proven to be a great series of articles so far and has arrived just at the right time for the project I'm working on! I can't wait for the third installment.



John

Thinking in Seam

Please provide an example to use JBoss Portal services with a4J by vineet tripathi

The sample application is wonderful to start with implementation of ajax on JSF portlet with JBoss portal. But when i send an ajax request using a4j to a bean action that uses Jboss -portal services , such as instanceContainer, PortalObjectContainer or userModule, i get an exception that says:
org.hibernate.HibernateException: Unable to locate current JTA transactio

Please provide an example that uses these services with ajax.

avoid "unable to locate current JTA transaction" for a4j & portal services by vineet tripathi

I got the solution for using JBoss portal services with a4j. The following is the solution
1)You need to demarcate your action with a JTA transaction:
/*
*
* Start transaction
*/
boolean isNewTransaction = true;
InitialContext ctx=null;
UserTransaction tx=null;
try{
ctx = new InitialContext();
tx = (UserTransaction)ctx.lookup("UserTransaction");
System.out.println("transaction tx is>>>>>>>>>>>>>"+tx);
tx.begin();
}catch(Exception e){
System.out.println("Exception occured>>>>>>"+e.getMessage());
isNewTransaction = false;
// e.printStackTrace();
}
/*
*
* Start transaction end
*/

/***Perform your actions by calling the JBoss portal services ****/

/**commit the transaction
*
*/
if(isNewTransaction){

try{
tx.commit();
System.out.println("Transaction commited *********************");
}catch(Exception e){
// log.info("Exception occured");
System.out.println("Exception>>>>>>"+e.getMessage());
}
}
/**
* commit the transaction
*/
If you are creating or destroying a portal object you need to load the object using following method to sync up your VO with Db:

portalObjectContainer.getObject(objectId);

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

3 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT