NEW!! FREE MOCK EXAM SIMULATORS FOR IBM PORTAL TEST 399 & IBM PORTLET CERTIFICATION EXAM TEST 829!!!
Everything You Ever Wanted To Know About JSR-168 Portlet Development . . . PORTAL + TUTORIAL = www.portorials.com
Google

The JSR-168 Struts Portlet

Framework JSR-168 Portlets: Struts and Java Server Faces

First of all, I want to say that frameworks are an advanced topic. Struts and JSF, running within a JSR-168 Portlet, is not a subject for a portlet neophyte to be tackling. However, many portlet developers have encountered a need for a framework that helps build multi-page, wizard-type portlets, that have complex state management requirements; struts and JSF portlets address this need.

These framework tutorials will attempt to do the following: demonstrate how to create a simple, JSR-168 compliant Struts and JSF portlet. (This tutorial deals with the struts framework)

Check Your Portal Server

These tutorials were developed based upon the apache portlet bridges. These tutorials will create struts and JSF portlet applications that will run and deploy to JetSpeed2. In fact, each development tutorial is followed by a deployment tutorial showing deployment to JetSpeed2. However, and this is a big however: each vendor is a little different. What works with a JetSpeed2 portlet might not work exactly the same way on JBoss or BEA WebLogic. There are nuances between vendors.

These tutorials will definitely help you understand the Struts and JSF portlet frameworks, but you should definitely cross-reference with your vendor's own documentation.

Apache Portals Bridges Homepage

Also, I just want to remind you that JSF and Struts are entire frameworks, that are written about in 500 page books. These tutorials will not teach you everything there is to know about Struts or JSF. In fact, it will only show you the basics, and it probably won't even do that all that well. Struts and JSF can't be described fully in a 10 minute tutorial. If you're new to Struts or JSF, ask for some guidance from someone in the know if you get a little confused about the finer points of the framework.

Enjoy the tutorials. And Happy Portal!
Framework JSR-168 Portlets: Struts and Java Server Faces

This is a very kewl tutorial. I highly recommend it!

Please support our site, link to us, buy some books, and remember: Happy Java!

Download the Code!!! (Scroll down and view the code)

Here's a link to download the completed, Rock-Paper-Scissors, Struts Portlet:Completed Struts Portlet

Here's a link to download the completed, Rock-Paper-Scissors, JSF Portlet:Completed Java Server Faces Portlet

The war file was created using IRAD 6, but it's only been tested on JetSpeed2, and I don't think it will run on WebSphere Portal Server. Check the apache bridges website for information on what needs to be tweaked to get it to run on your portal platform of choice.

Apache Portals Bridges Homepage

portlet.xml File for JSR-168 Struts Portlet

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
id="RockPaperScissorsStrutsPortlet.1c7992b209">

<portlet id="RockPaperScissorsStrutsPortlet2.id99">

<description>RockPaperScissors 99</description>
<portlet-name>RockPaperScissors 99</portlet-name>
<display-name>RockPaperScissors 99</display-name>
<portlet-class>
org.apache.portals.bridges.struts.StrutsPortlet
</portlet-class>
<init-param>
<name>ServletContextProvider</name>
<value>
org.apache.jetspeed.portlet.ServletContextProviderImpl
</value>
</init-param>
<init-param>
<name>ViewPage</name>
<value>/index.mcnz</value>
</init-param>

<!-- you can add additional modes, such as help
<init-param>
<name>HelpPage</name>
<value>/help.mcnz</value>
</init-param>
end of commented out help mode -->

<expiration-cache>-1</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
<portlet-info>
<title>RockPaperScissors</title>
<keywords>Struts</keywords>
</portlet-info>
</portlet>
</portlet-app>





web.xml File for Struts JSR-168 Portlet

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebApp_ID_0077">
<display-name>RockPaperScissorsStrutsPortlet 99</display-name>
<description>RockPaperScissorsStrutsPortletProject 99</description>


<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.portals.bridges.struts.PortletServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>detail</param-name>
<param-value>2</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.mcnz</url-pattern>
</servlet-mapping>

<session-config>
<session-timeout>30</session-timeout>
</session-config>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>

</web-app>






Landing Page (index.jsp) for Struts JSR168 Portlet

<%@ page contentType="text/html"%>
<%@ taglib
uri="http://portals.apache.org/bridges/struts/tags-portlet-html"
prefix="html"%>

<TABLE border=0 cellSpacing=0 width="100%">
<TR>
<TD vAlign=top width=100%>
<html:form action="rpsaction">
What's it going to be? Rock, paper or scissors?
<html:text property="rpschoice"></html:text>
<input type="submit" name="submit" value="submit">
</html:form>
</TD>
</TR>
</TABLE>


struts-config.xml File for Struts Portlet

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
<form-beans>


<form-bean name="rpsform"
type="org.apache.struts.action.DynaActionForm">
<form-property name="rpschoice" type="java.lang.String" />
</form-bean>

</form-beans>

<action-mappings>


<action path="/rpsaction"
type="com.examscam.portlet.action.RockPaperScissorsAction"
name="rpsform" scope="request" validate="false" input="index.jsp">

<forward name="win" path="/win.jsp" redirect="true" />
<forward name="lose" path="/lose.jsp" redirect="true" />
<forward name="tie" path="/tie.jsp" redirect="true" />
</action>

<action path="/index" include="/index.jsp" />
<!-- CATALOG ACTIONS -->

</action-mappings>

<controller pagePattern="$M$P" inputForward="false"
processorClass="org.apache.portals.bridges.struts.PortletRequestProcessor" />

</struts-config>




win.jsp File forJSR-168 Struts Portlet



<%@ taglib uri="http://portals.apache.org/bridges/struts/tags-portlet-html" prefix="html" %>
<%@ page contentType="text/html"%>

<P>I chose rock. I WIN!!!</P>


lose.jsp File for JetSpeed JSR-168 Struts Portlet


<%@ taglib uri="http://portals.apache.org/bridges/struts/tags-portlet-html" prefix="html" %>
<%@ page contentType="text/html"%>


<P>Paper beats rock. YOU WIN!!!</P>



tie.jsp File for JSR-168 Struts Portlet


<%@ taglib uri="http://portals.apache.org/bridges/struts/tags-portlet-html" prefix="html" %>
<%@ page contentType="text/html"%>


<P>Rock is always a good call: TIE</P>



Action Class (Controller) Java Code for JSR-168 Struts Portlet

package com.examscam.portlet.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

public class RockPaperScissorsAction extends Action

{

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {

ActionForward forward = new ActionForward();
DynaActionForm choiceForm = (DynaActionForm)form;


try {

String choice = (String)choiceForm.get("rpschoice");
System.out.println(choice);
if (choice.equalsIgnoreCase("rock")){
forward = mapping.findForward("tie");
}
if (choice.equalsIgnoreCase("paper")){
forward = mapping.findForward("lose");
}
if (choice.equalsIgnoreCase("scissors")){
forward = mapping.findForward("win");
}

} catch (Exception e) {
System.out.println(e.getMessage()+e.getClass());
forward = mapping.findForward("win");
}
return (forward);

}
}



struts-portlet-config.xml File for JSR-168 Struts Portlet

<?xml version="1.0" encoding="UTF-8"?>

<config>
<portlet-url-type>
<action path="/rpsaction" />
</portlet-url-type>
</config>







Portlet Frameworks Portal Frameworks So far, the portlets we have looked at have been relatively stateless. Our portlets might take a small piece of data from a user, and display back a response, but none of the portlets we have developed incorporate multiple pages, that must be completed in a step by step manner. What happens when we need a wizard-type of application that requires the user to fill out multiple forms in a specific sequence or order? The portlet API, not to mention the portal as a whole, doesn?t really provide any built in facilities for developing a wizard-like, multi-state, multi-page application, yet these types of apps are quite common in a typical enterprise environment. Creating ?Wizard Type? Portlet Applications Imagine a web based application such as an online exam, where a user can select a topic on which to be examined, a user can start an exam, can finish an exam, and can even jump between different questions while an exam is in progress. An application like this would incorporate many different presentation pages. An exam application like this would also incorporate several different application states, such as an examinprogressstate, examgradedstate, topicselectedstate and topicnotselectedstate. Depending upon which state a user is in, only certain page transitions would be legal, and it would be the job of the developer to ensure that any illegal page transition didn?t mess up the user?s application. How do we perform complex state management such as this in a portlet application? Form Handling and Error Validation Furthermore, if we are developing an application that takes a great deal of input from the user, how do we handle input-form validation? And if a user indeed provides bad data, what type of framework are we going to use to provide internationalized error messages back to the user? The portal API doesn?t provide any built in facilities for implementing form handling, or for delivering helpful error messages back to the user. Fortunately though, there are a number of different frameworks on the market with built-in facilities for managing complex application state, multi-page navigation, error handling and input validation. The most pervasive application development frameworks in the Java arena are Struts and Java Server Faces (JSF). For developers who want to create complex portlet applications, not to mention those who want to port existing Struts and JSF applications to the portal, a variety of bridges exist to make it possible to create JSR-168 compliant Struts and JSF portlet applications. The Rock- Paper-Scissors Struts Portlet To help demonstrate the struts portet framework, we?ll recreate the old Rock-Paper-Scissors challenge. Of course,we?ll always choose rock, because rock rocks. When the user chooses rock as well, it?s a tie; if the user chooses paper, they win; and if the user chooses scissors, they lose. Figure xxx-sss shows what the landing page of our portlet will look like, and the three potential outcomes of the game. Figure xxx-sss We will use the Rock-Paper-Scissors challenge to guide us through the creation of the struts portlet. First Step The first step in developing a struts portlet is to create an empty portlet project, with the proper folder structure needed for a regular JSR168 portlet app. From there, you must download the required JAR files that are needed to get a JSR168 struts portlet to work. The following jar files must be downloaded from apache, and added to the lib directory of the portlet application: · commons-beanutils-1.7.0.jar · commons-digester-1.6.jar · commons-fileupload-1.0.jar · commons-logging-1.0.4.jar · commons-validator-1.1.4.jar · log4j-1.2.8.jar · portals-bridges-struts-1.2.7-1.0.jar · standard-1.0.6.jar · struts-1.2.7.jar · struts-el-1.2.7.jar Step Two: Edit portlet.xml File After adding the required JAR files to the lib directory, the portlet.xml file must be edited to define a portlet that uses the struts bridge. <?xml version="1.0" encoding="UTF-8"?> <portlet-app xmlns="http://java.sun.com/xml/nsortletortlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/nsortletortlet-app_1_0.xsd http://java.sun.com/xml/nsortletortlet-app_1_0.xsd" id="RockPaperScissorsStrutsPortlet.1c7992b209"> <portlet id="RockPaperScissorsStrutsPortlet2.id9"> <description>RockPaperScissors</description> <portlet-name>RockPaperScissors<ortlet-name> <display-name>RockPaperScissors</display-name> <portlet-class> org.apache.portals.bridges.struts.StrutsPortlet <ortlet-class> <init-param> <name>ServletContextProvider</name> <value> org.apache.jetspeed.portlet.ServletContextProviderImpl </value> </init-param> <init-param> <name>ViewPage</name> <value>/index.mcnz</value> </init-param> <!-- You can optionally add additional portlet modes <init-param> <name>HelpPage</name><value>/help.mcnz</value> </init-param> end of commented out help mode --> <expiration-cache>-1</expiration-cache> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW<ortlet-mode> <portlet-mode>HELP<ortlet-mode> </supports> <portlet-info> <title>RockPaperScissors</title> <keywords>Struts</keywords> <ortlet-info> <ortlet> <ortlet-app> Step Three: Edit the web.xml File After editing the portlet.xml file, the web.xml file must be made aware of the PortletServlet, which is essentially the bytecode embodiment of the JSR-168 Struts Portlet bridge. Typical portlet applications don?t edit the web.xml file too often, but this is a total requrement to get the struts framework to run within a JSR-168 compliant portlet. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" http://java.sun.com/dtd/web-app_2_3.dtd > <web-app id="WebApp_ID_0077"> <display-name>RockPaperScissors</display-name> <description>RockPaperScissors</description> <servlet> <servlet-name>action</servlet-name> <servlet-class> org.apache.portals.bridges.struts.PortletServlet </servlet-class> <init-param> <param-name>config<aram-name> <param-value>/WEB-INF/struts-config.xml<aram-value> </init-param> <init-param> <param-name>debug<aram-name> <param-value>2<aram-value> </init-param> <init-param> <param-name>detail<aram-name> <param-value>2<aram-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.mcnz</url-pattern> </servlet-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app> Step Four: Create the Landing Page Every portlet must support the view mode, and the struts portlet is no exception. The page we create, that is by default, displayed when the portal in view mode, can be referred to as the landing page. Since we are modeling the old rock, paper, scissors game, our landing page will contain a form that asks the user to type in one of three words: rock, paper or scissors. <%@ page contentType="text/html"%> <%@ taglib uri="http:/ortals.apache.org/bridges/struts/tags-portlet-html" prefix="html"%> <TABLE border="0" cellSpacing="0" width="100%"> <TR> <TD vAlign="top" width="100%"><html:form action="rpsaction"> What's it going to be? Rock, paper or scissors? <html:text property="rpschoice"></html:text> <input type="submit" name="submit" value="submit" /> </html:form></TD> </TR> </TABLE> You should notice two things right away about this example. First, the HTML uses custom tags for defining all of the form elements, including: the form itself, the textfield and the submit button. These custom tags are part of the Struts library, and help with both the implementation of the view layer, and the process of communicating input data back to the control layer of the application. Struts works very tightly with a model-view-controller philosophy. Secondly, you should notice that the taglib directive references the struts-portal custom tag library. For struts programmers, this is unique, as it is not a reference to the standard struts custom tags. For portlet developers, this is different, as it is not a reference to the portletAPI custom tag library. This set of custom tags is based primarily on the struts API, and the custom tags traditionally afforded to a regular struts application, although they have been tweaked a little to support the JSR-168 portlet specification. Creating the struts-config.xml File You will notice that while the web.xml and portlet.xml file had a number of entries that references resources packaged in the various JAR files downloaded from apache.org, there was no reference to any resources that the developer will code to implement their custom application. This is because, in a struts application, all of the information about how the developer?s application works is configured in the appropriately named, struts-config.xml file. The struts-config.xml file resides in the same folder as the portlet.xml and web.xml files, which is the \WEB-INF folder, off the root of the war file. <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd > <struts-config> <action-mappings> <action path="/index" include="/index.jsp" /> </action-mappings> <controller pagePattern="$M$P" inputForward="false" processorClass="org.apache.portals.bridges.struts.PortletRequestProcessor" /> </struts-config> There are two important things to note about the content of the struts-config.xml file. First, is the action mapping from /index to /index.jsp. The /index action mapping is used by the view mode of a struts portlet to display content when the portlet is first rendered. We have this action mapped to our landing page, index.jsp. <action path="/index" include="/index.jsp" /> Furthermore, the second, more innocuous entry in the struts-config.xml file, is the reference to the PortletRequestProcessor as the controller for the application. This entry can usually be left alone, although it should be noted that different vendors may provide their own controller. For example, for an IBM Struts portlet, the controller is the xxxwpsclass. Furthermore, in the past, when struts portlet applications misbehaved, such as having the action processing phase being invoked twice or something, sometimes this particular class has to be upgraded or changed. For the most part though, this entry can be left alone. Adding the DynaActionForm Entry One of the compelling features of struts, is the built-in ability of the framework to both validate client input, and pass that input to the controller part of the application. The component used to pass form input data from the client view to the server side struts controller, is known as an ActionForm object. Complex input validation can be coded into a class that inherits from ActionForm, and subsequently gets called when client input is submitted to the server. <form-beans> <form-bean name="rpsform" type="org.apache.struts.action.DynaActionForm"> <form-property name="rpschoice" type="java.lang.String" /> </form-bean> </form-beans> Alternatively, rather than sub-classing ActionForm, an entry can be made in the struts-config.xml file that defines a dynamic form. This dynamic form object, or DynaActionForm, as it is offictially called, is created on the fly by the struts framework, and will be used to magically pass the data entered by the user on the client side, to the struts action components running on the serverside. For our application, we will map the textfield on our landing page, which is named rpschoice, to a dynaform entry named rpsform, which encapsulates the data entered into the rpschoice textfield. Here is how our struts-config.xml file is progressing: <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd > <struts-config> <form-beans> <form-bean name="rpsform" type="org.apache.struts.action.DynaActionForm"> <form-property name="rpschoice" type="java.lang.String" /> </form-bean> </form-beans> <action-mappings> <action path="/index" include="/index.jsp" /> </action-mappings> <controller pagePattern="$M$P" inputForward="false" processorClass="org.apache.portals.bridges.struts.PortletRequestProcessor" /> </struts-config> Create the Results Pages Since this is the rock, paper, scissors game we are emulating, there will be three potential outcomes: win, lose or tie. While it might not be the most efficient application design, in an attempt to emphasize the ability struts provides for managing multi-page applications, we will create three separate JSP pages, one for each of the potential outcomes: win.jsp, lose.jsp, and tie.jsp. These will be simple pages that simply say You win!, You lose!, or We tied! win.jsp <%@ taglib uri="http:/ortals.apache.org/bridges/struts/tags-portlet-html" prefix="html"%> <%@ page contentType="text/html"%> <P>Paper beats rock. YOU WIN!!!<> lose.jsp <%@ taglib uri="http:/ortals.apache.org/bridges/struts/tags-portlet-html" prefix="html"%> <%@ page contentType="text/html"%> <P>I chose rock. I WIN!!!<> tie.jsp <%@ taglib uri="http:/ortals.apache.org/bridges/struts/tags-portlet-html" prefix="html"%> <%@ page contentType="text/html"%> <P>Rock is always a good call: TIE<> Debriefing the Results Pages The win.jsp, lose.jsp and tie.jsp pages are all relatively straight forward. They include a reference to the struts-portlet custom tag library, although none of them actually use the struts-portlet tags. Defining the Action Class in struts-config.xml As you have probably gathered, the struts-config.xml file is pretty pivotal when it comes to developing a struts application. Within the struts-config.xml file, we have already defined the controlling request processor, an /index path, which represents the landing page of our portlet, and a form-bean object, which will be used to marshal input data back and forth between the client and our server side application. The only thing we are missing is an entry for the action class we are about to code, which will implement the control and flow logic for our application. We are going to code logic into a custom struts action class called RockPaperScissorsAction, which will be found in the package com.examscam.portlet.action. This action will be invoked by the index.jsp file, and when it is invoked, it will be passed an instance of our form bean, the rpsform, which encapsulates the client input in a field named rpschoice. Furthermore, there will be three possible outcomes from invoking this action, namely win, lose, or tie, which map to the correspondingly named JSP pages win.jsp, lose.jsp and tie.jsp. All of this information must be captured in the struts-config.xml file, as so: <action path="/rpsaction" type="com.examscam.portlet.action.RockPaperScissorsAction" name="rpsform" scope="request" validate="false" input="index.jsp"> <forward name="win" path="/win.jsp" redirect="true" /> <forward name="lose" path="/lose.jsp" redirect="true" /> <forward name="tie" path="/tie.jsp" redirect="true" /> </action> The Completed struts-config.xml File <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd > <struts-config> <form-beans> <form-bean name="rpsform" type="org.apache.struts.action.DynaActionForm"> <form-property name="rpschoice" type="java.lang.String" /> </form-bean> </form-beans> <action-mappings> <action path="/rpsaction" type="com.examscam.portlet.action.RockPaperScissorsAction" name="rpsform" scope="request" validate="false" input="index.jsp"> <forward name="win" path="/win.jsp" redirect="true" /> <forward name="lose" path="/lose.jsp" redirect="true" /> <forward name="tie" path="/tie.jsp" redirect="true" /> </action> <action path="/index" include="/index.jsp" /> </action-mappings> <controller pagePattern="$M$P" inputForward="false" processorClass="org.apache.portals.bridges.struts.PortletRequestProcessor" /> </struts-config> Creating the Struts Action Class All of the required entries have been made to the struts-config.xml file, and all of our JSP pages have been created. Now it?s time to code the struts Action class. In struts, the control logic goes into action classes, which inherit from the special struts class, appropriately named, Action. In this action class, we code a very special method called execute, which not only gets passed the standard request and response objects, but more interestingly, it gets passed the ActionForm that encapsulates any data that has been sent to the server by the client, along with another special object called the ActionMapping object, which can read the various forward entries in the struts-config.xml file, and subsequently generate an ActionForward object. The job of the execute method is to figure out where to send the client next; correspondingly, the return type of the execute method is a special struts class called an ActionForward. Please, Cut Me Some Slack!!! If you?re new to struts, this is all probably pretty overwhelming. I want to emphasize that struts is an entire book on its own, and I?m trying to fit the pertinent parts into a small chapter. If you are doing struts development, you really owe it to yourself to pick up a book that explains the technology in greater detail. Better yet, find someone on your team that might be able to walk you through this tutorial and point out some of the finer points of struts development. Please don?t judge this book on this short chapter on the struts framework. J package com.examscam.portlet.action; import javax.servlet.http.*; import org.apache.struts.action.*; public class RockPaperScissorsAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward forward = new ActionForward(); DynaActionForm choiceForm = (DynaActionForm)form; try { /* Use the DynaActionForm to find get the form input*/ String choice = (String)choiceForm.get("rpschoice"); /* Given the users choice,forward to the appropriate view page*/ if (choice.equalsIgnoreCase("rock")){ forward = mapping.findForward("tie"); } if (choice.equalsIgnoreCase ("paper")){ forward = mapping.findForward("lose"); } if (choice.equalsIgnoreCase ("scissors")){ forward = mapping.findForward("win"); } /* Be lazy, and just send to win if there is a problem. */ } catch (Exception e) { System.out.println(e.getMessage()+e.getClass()); forward = mapping.findForward("win"); } /* the end of a struts action forwards to a view page*/ return (forward); } } Adding the struts-portlet-config.xml File One place a struts portlet differs from a regular struts application is with the requirement for a special configuration file named struts-portlet-config.xml. This file goes along side the struts-config.xml file and the portlet.xml and web.xml deployment descriptors in the WEB-INF folder. Essentially, every custom action mapping that appears in the struts-config.xml file should have a corresponding entry in the struts-portlet-config.xml file. <?xml version="1.0" encoding="UTF-8"?> <config> <portlet-url-type> <action path="/rpsaction" /> <ortlet-url-type> </config> Package and Deploy! Once the struts-portlet-config.xml file is successfully added, you are now ready to package your portlet application in a war file, and deploy the war to the portal server. Again, this particular tutorial demonstrates how to build a struts portlet that can be deployed to a JetSpeed2 portal server. Each platform has its own nuances, and this particular portlet may not run on every portal platform. If you?re not developing on JetSpeed2, this tutorial will help to point you in the right direction, but you should definitely check your vendor?s documentation with regards to how to tweak the apache bridge, or the struts framework as a whole, to get the struts framework to run in your environment. Struts and Portalxxx WebSphere Portal supports the Struts framework by allowing developers to create state sensitive, wizard type portlet applications, and portlet applications that require complex error handling and form validation, just as easily as they would any other Struts application. As the WebSphere Portal 5.1 certification exam was developed, Struts support, and even more so, JSF support in the development tool was minimal. As a result, extensive knowledge of implementing Struts and JSF type of applications is not required for certification success. However, knowledge of the fact that the Struts and JSF frameworks make sense when creating complex portlet applications is required. Furthermore, a couple of questions about the basics of a Struts portlet is to be expects. Developing A Struts Portlet from Scratch Rather than being wizards based, developing a Struts Portlet begins by importing a blank, Struts Portal application into the workspace. This provides the basic framework for JSR-168 Struts success, which means the struts-config.xml, portlet.xml and web.xml files are appropriately configured, and the appropriate jar files are stuffed in the lib directory of the web module. Coding a Struts application is all about coding Action objects, and the Struts Portlet is no different, although a special class, called the StrutsAction, or even the com.ibm.portal.struts.action.DispatchAction for more complicated navigation, is extended, as opposed to the standard Struts Action class. Of course, all Actions, forwards and validating forms must be configured in the struts-config.xml file. The struts-config.xml file in a portlet application is pretty much the normal struts-config.xml file, with the main exception being the controller class being specified as the WpRequestProcessor. Communicating between portlets has always been a challenge for Portlet developers. Traditionally, sessions have not been shared between portlets, and even PortletPreferences are not typically shared amongst Portlets of the same type on the same page. The IBM Legacy Portlet APIs provided mechanisms to communicate messages between portlets on the same page, but these features fall short when it becomes necessary to message between portlets that reside on different nodes of the portal. To address the downfalls of standard portlet messaging, IBM has introduced a sexy and exciting technology called Click-to-Action (C2A). l Chapter xxxJSF Portlet Development A discussion of JSR-168 portlet development wouldn?t be complete without a discussion of how to leverage the Java Server Faces (JSF) development framework within the confines of a JSR-168 portlet. Like struts, JSF is a highly pervasive, model-view-controller (MVC) framework for developing web based applications. JSF not only incorporates a number of important design patterns and development best practices, but it also provides facilities for managing many of those difficult challenges that typically stare down web based developers, such as managing application state, providing input validation, and providing feedback to a user when an error has occurred. A JSF portlet application begins with the same basic structure as any other portlet application, with a WEB-INF folder that contains both a web.xml and portlet.xml file, and a \WEB-INF\lib folder containing all of the required JAR files. Acquiring the Required JAR Files A JSF portlet application requires a number of supporting JAR files to work. Some of these JAR files are required for developing against the basic JSF framework, whereas others provide common JSF extensions. Furthermore, the portals-bridges-jsf-1.0.jar actually contains the JSF-portal bridge that allows a JSF application to be ported to a portlet environment. The following JAR files should be added to the lib directory of the JSF portlet application: · commons-beanutils-1.6.1.jar · commons-codec-1.2.jar · commons-collections-2.1.jar · commons-digester-1.5.jar · commons-el-1.0.jar · commons-logging-1.0.4.jar · log4j-1.2.8.jar · myfaces-api-1.1.0.jar · myfaces-impl-1.1.0.jar · portals-bridges-jsf-1.0.jar · tomahawk-1.1.0.jar Updating the web.xml File A standard JSF application requires a number of entries to be made to the web.xml file, including a number of context parameters, the definition of the JSF FacesServlet, and the mapping of the FacesServlet to *.faces. One of the things you should notice about the web.xml file of a JSF-Portlet application is the fact that there aren?t any references to portlet packages, not even for the definition of the FacesServer, javax.faces.webapp.FacesServlet. One of the compelling reasons for using JSF, especially in a portlet environment, is the fact that JSF is extremely portlet friendly, much more so than struts, and for the most part, relatively few changes need to be made to get an existing portlet application to run inside of the portal. <?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class> javax.faces.webapp.FacesServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <context-param> <param-name>javax.faces.CONFIG_FILES<aram-name> <param-value>/WEB-INF/faces-config.xml<aram-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD<aram-name> <param-value>client<aram-value> </context-param> <context-param> <param-name> org.apache.myfaces.ALLOW_JAVASCRIPT <aram-name> <param-value>true<aram-value> </context-param> <context-param> <param-name>org.apache.myfaces.PRETTY_HTML<aram-name> <param-value>true<aram-value> </context-param> <context-param> <param-name> org.apache.myfaces.DETECT_JAVASCRIPT<aram-name> <param-value>false<aram-value> </context-param> <context-param> <param-name>org.apache.myfaces.AUTO_SCROLL<aram-name> <param-value>true<aram-value> </context-param> <!--continued on next page --> <!--continued from previous page --> <listener> <listener-class> org.apache.myfaces.webapp.StartupServletContextListener </listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> The JSF Configuration File In my opinion, the most elegant aspect of JSF development is the manner in which the crucial elements of page navigation are tied together in the JSF configuration file, faces-config.xml For example, in our Rock-Paper-Scissors example, we will have a landing page, named index.jsp, that contains an input form that is used to take data from the user. User input will be delivered to a Java class that acts as a controller, and the controller will decide which one of three jsp files, win.jsp, lose.jsp or tie.jsp, will be displayed back to the user. This is all elegantly detailed in the faces-config.xml file as follows: <navigation-rule> <from-view-id>/index.jsp</from-view-id> <navigation-case> <from-outcome>win</from-outcome> <to-view-id>/win.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>lose</from-outcome> <to-view-id>/lose.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>tie</from-outcome> <to-view-id>/tie.jsp</to-view-id> </navigation-case> </navigation-rule> Managed Beans The custom-coded, logic controller, that handles the client request and figures out which of the possible outcomes to which a client should be routed, also gets referenced in the faces-config.xml file. We are going to code a Java controller, named RockPaperScissorsController, which we?ll throw in the package com.examscam.rps.jsf. Here is how the faces-config.xml file entry for the RockPaperScissorsConroller will look: <managed-bean> <managed-bean-name>rpscontroller</managed-bean-name> <managed-bean-class> com.examscam.rps.jsf.RockPaperScissorsController </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> The name, rpscontroller, is the name we will use when invoking this component from the HTML page. The JSF framework will then map the managed-bean-name back to the implementation class, RockPaperScissorsController. The Full faces-config.xml File There is undoubtedly a great deal of information that can be entered in the faces-config.xml file. However, we?re going to keep this example as succinct an simple as possible. The following is the full faces-confg.xml file for this example. Remember, the faces-config.xml file must be placed in the \WEB-INF folder of the portlet application. <?xml version="1.0"?> <!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN" "http://java.sun.com/dtd/web-facesconfig_1_0.dtd"> <faces-config> <navigation-rule> <from-view-id>/index.jsp</from-view-id> <navigation-case> <from-outcome>win</from-outcome> <to-view-id>/win.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>lose</from-outcome> <to-view-id>/lose.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>tie</from-outcome> <to-view-id>/tie.jsp</to-view-id> </navigation-case> </navigation-rule> <managed-bean> <managed-bean-name> rpscontroller </managed-bean-name> <managed-bean-class> com.examscam.rps.jsf.RockPaperScissorsController </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> </faces-config> The Landing Page: index.jsp The page that is first displayed by the JSF portlet, also known as the landing page, will be named index.jsp. This page uses the core and html JSF custom tag libraries to create a form that will take input from the user, and subsequently be submitted to the server. <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <f:view> <h:form id="rpsform"> Rock Paper or Scissors? <h:inputText id="rpschoice" /> <BR /> <h:commandButton value="What will it be???" action="#{rpscontroller.play}" /> <BR /> </h:form> </f:view> Notice the id attribute of the form and the inputText field, rpsform and rpschoice. To extract what the user has typed into the textfield associated with this form, we will use the call: request.getParameter(?rpsform:rpschoice?); Also noteworthy is the value of the action attribute, #{rpscontroller.play}. This is part of the JSF expression language, and in plain terms, it reads: when the submit button of the form is clicked, invoke the managed bean named rpscontroller, and call the play method of that bean. The name rpscontroller is mapped to the RockPaperScissorsController class in the faces-config.xml file. The RockPaperScissorsController is the Java class we will code that contains all of the control logic for the Rock-Paper-Scissors application. <managed-bean> <managed-bean-name>rpscontroller</managed-bean-name> <managed-bean-class> com.examscam.rps.jsf.RockPaperScissorsController </managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> The Managed Bean: RockPaperScissorsController The faces-config.xml file refers to a managed-bean named RockPaperScissorsController. This is a custom coded class that implements the core logic of our application, or at least, the core logic associated with page navigation. A JSF application can have any number of managed beans associated with it. The more complicated the site, and the more numerous the number of page changes and state transitions, more managed beans will be required. Our simple application will use one, but this is more the exception, not the rule. Unlike struts, where controllers must subclass the struts Action class, JSF controllers can be simple classes that inherit directly from java.lang.Object. Furthermore, the developer has the freedom to call their action, or control logic method, anything they want. In our case, we will create a class that extends java.lang.Object, with a simple controlling method called play(). package com.examscam.rps.jsf; import javax.faces.context.*; import javax.servlet.http.*; public class RockPaperScissorsController { public String play() { /*Implement logic here, and return a String, corresponding to one of the from-outcome entries in the faces-config.xml file, such as win,lose or tie.*/ } } The key to coding your controller methods is the fact that they must return a String, and that String must map to a from-outcome entry in the faces-config.xml file. The three from-outcome entries available to our controller, according to the faces-config.xml file, are: win, lose and tie. Request-Response Programming Unlike the execute method of a struts action class, the doPost of a Servlet, or the doView method of a portlet, methods of a JSF managed-bean are not explicitly passed a request and response object. Instead, to access the request and response objects, a static call needs to be made to the FacesContext, which returns an ExternalContext. From the ExternalContext, you can access the important objects of the Servlet and JSP API, namely the HttpServletRequest, and the HttpServlerResponse. """ ExternalContext context = FacesContext.getCurrentInstance().getExternalContext(); HttpServletRequest request = (HttpServletRequest) context.getRequest();""" Once we have the request object, we can figure out what the user typed into the form they just submitted, and send the user to the appropriate page: """ String result = null; String choice = request.getParameter("rpsform:rpschoice"); /*we always chose ROCK*/ if (choice.equalsIgnoreCase("PAPER")){ result = "win";} if (choice.equalsIgnoreCase("SCISSORS")){result = "lose";} if (choice.equalsIgnoreCase("ROCK")){result = "tie";} return result; """ Notice how the result maps to one of the three navigation-case elements in the faces-config.xml file. <navigation-case> <from-outcome>win</from-outcome><to-view-id>/win.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>lose</from-outcome><to-view-id>/lose.jsp</to-view-id> </navigation-case> <navigation-case> <from-outcome>tie</from-outcome><to-view-id>/tie.jsp</to-view-id> </navigation-case> It should be noted that if a null String is returned, the JSF framework simply redisplays the originating page to the user. The Full RockPaperScissorsController package com.examscam.rps.jsf; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; public class RockPaperScissorsController { public String play() { /*Gain access to the request object*/ ExternalContext context = FacesContext.getCurrentInstance() .getExternalContext(); HttpServletRequest request = (HttpServletRequest)context.getRequest(); String result = null; /*Grab the user?s input from the form*/ String choice = request.getParameter("rpsform:rpschoice"); /* we always chose ROCK */ if (choice.equalsIgnoreCase("PAPER")){ result = "win"; } if (choice.equalsIgnoreCase("SCISSORS")){ result = "lose"; } if (choice.equalsIgnoreCase("ROCK")){ result = "tie"; } /*return the navigation string to the JSF framework*/ return result; } } The JSP Files The navigation-case in the faces-config.xml file lists three JSP files, win.jsp, lose.jsp and tie.jsp, as possible outcomes. These three, simple JSP files, will be placed in the root of the portlet application, in the same directory as the WEB-INF folder. <!-- win.jsp --> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <H1>You WIN!</H1> <H2>Paper beats rock. You win!</H2> <!-- lose.jsp --> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <H2>Rock beats scissors. You lose!!!</H2> <!-- tie.jsp --> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <H2>Rock is always a good call: TIE</H2> Each of the JSP files reference the html and core JSF tag libraries. Since no tags are actually being used in the JSP files, the declarations are not needed, but I threw them in to emphasize the fact that they are often used in a JSF application. Moving to the Portlet World Believe it or not, but so far, we?ve developed a completely valid, JSF application, that could run quite ruggedly in any standard Servlet and JSP container. We really haven?t done anything portlet specific. This is actually the great thing about porting JSF applications to the portal world ? there is very little configuration that needs to be done once the JSF application is working properly. To portalize a JSF application, the toughest part is creating the portlet.xml file. <?xml version="1.0" encoding="UTF-8"?> <portlet-app id="jsf-demo" version="1.0"> <portlet> <description>JSF RPS Portlet</description> <portlet-name>JSF RPS Portlet<ortlet-name> <display-name>JSF RPS Portlet</display-name> <portlet-class> org.apache.portals.bridges.jsf.FacesPortlet <ortlet-class> <init-param> <name>ViewPage</name><value>/index.jsp</value> </init-param> <init-param> <name>HelpPage</name><value>/help.jsp</value> </init-param> <init-param> <name>EditPage</name><value>/edit.jsp</value> </init-param> <expiration-cache>-1</expiration-cache> <supports> <mime-type>text/html</mime-type> <portlet-mode>VIEW<ortlet-mode> <portlet-mode>EDIT<ortlet-mode> <portlet-mode>HELP<ortlet-mode> </supports> <portlet-info> <title>JSF RPS Portlet</title> <ortlet-info> <ortlet> <ortlet-app> Examining the JSF portlet.xml File For the most part, the portlet.xml file associated with a JSF portlet is made up of all of the usual suspects, such as the name, description, title, etc. The key to the JSF portlet is the fact that the portlet-class entry maps to the JSF bridge from apache, or more specifically: org.apache.portals.bridges.jsf.FacesPortlet <portlet-class> org.apache.portals.bridges.jsf.FacesPortlet <ortlet-class> The other unique part of the JSF portlet.xml file is the init-param elements. For each of the various portlet modes you want your JSF portlet to support, you define an init-param element, with the mode as the name element, and the page to be rendered by default when that mode is invoked, as the associated value. Since we want our landing page, index.jsp, to display when the portlet is initially displayed in the view mode, we specify /index.jsp as the value for the named parameter ViewPage. <init-param> <name>ViewPage</name> <value>/index.jsp</value> </init-param> Multiple Modes with the JSF Portlet The portlet.xml file allows you to specify any number of supported modes for the JSF portlet. To support multiple modes, simply make the required entries under the support tag, as you would with any portlet, and then add init-param entries for each of the supported modes, using HelpPage and EditPage as the named value for the name-value pair. The value in the pair should point to the landing page for the given mode. <init-param> <name>HelpPage</name><value>/help.jsp</value> </init-param> <init-param> <name>EditPage</name><value>/edit.jsp</value> </init-param> The last thing our JSF portlet application needs is the JSF files that will act as landing pages for the help and edit modes: <!-- The edit.jsp file --> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <P>This is the edit mode. <!-- The help.jsp file --> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%><> <P>This is the help mode. Admittedly, the edit and help mode JSP files are pretty lame, but they do the job. Potentially, these pages could also take advantage of navigation and state management configured through a faces-config.xml file.<>
Google



eXTReMe Tracker

ActionRequest ActionResponse GenericPortlet PortletRequestDispatcher . Portlet ..... PortletURL
PortletContext PortletException PortletMode a PortletModeException PortletPreferences
PortalContext PortletResponse PortletSession PortletSecurityException PreferencesValidator
PortletConfig RenderRequest RenderResponse UnavailableException PortletSessionUtil
PortletRequest ValidatorException WindowState WindowStateException UnmodifiableException