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
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.
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
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.
<!-- 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 -->
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.<>