Developing Portlets using JSF, Ajax, and Seam (Part 2 of 3)
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.
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.
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.
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>
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:
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:
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...)
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.
Excellent series so far!
Thinking in Seam
Please provide an example to use JBoss Portal services with a4J
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
1)You need to demarcate your action with a JTA transaction:
* Start transaction
boolean isNewTransaction = true;
ctx = new InitialContext();
tx = (UserTransaction)ctx.lookup("UserTransaction");
System.out.println("transaction tx is>>>>>>>>>>>>>"+tx);
isNewTransaction = false;
* Start transaction end
/***Perform your actions by calling the JBoss portal services ****/
/**commit the transaction
System.out.println("Transaction commited *********************");
// log.info("Exception occured");
* 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: