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
Strictly speaking, the various do methods of a portlet should only
be responsible for generating the markup that needs to be sent back
to the client. Since portlet mode methods, such as doView, doEdit,
doConfigure and doHelp, are really only intended for generating the
markup that gets sent back to the client, those methods are said to
be part of the portlet?s rendering phase, and as such, these methods
are passed a RenderRequest and a RenderResponse object.
Two Phase Portlet Processing
Tasks such as state management, form handling and PortletSession
management should not take place during the portlet rendering phase.
In fact, certain tasks, such as the manipulation the
PortletPreferences object associated with the doEdit mode, or forcing
a portlet to display itself in a maximized state, simply can?t be
performed during the portlet rendering phase. Such tasks must be
performed before a portlet is asked to render itself, during an
important stage known as the event processing or action processing
phase. The event processing phase is associated with a special method
called processAction.
This portorial examines how to take advantage of the action
processing phase of a portlet.
Please support our site, link to us, buy some books, and remember:
Happy Java!
Download the Code!!! (Scroll down and view the code)
Action Processing So far, our exposure
handing cient requests through a portet has imited itsef to the
rendering phase of portet processing ? a of our exampes have paced code
in the doView method of our portets. In our exampes, everything from
form handing, to view generation, has been done in the doView method.
However, this reay isn t a good deveopment practice. Stricty speaking,
the various do methods of a portet shoud ony be responsibe for
generating the markup that needs to be sent back to the cient. Since
portet mode methods, such as doView, doEdit, doConfigure and doHep, are
reay ony intended for generating the markup that gets sent back to the
cient, those methods are said to be part of the portet s rendering
phase, and as such, these methods are passed a RenderRequest and a
RenderResponse object. Two Phase Portet Processing Tasks such as state
management, form handing and PortetSession management shoud not take
pace during the portet rendering phase. In fact, certain tasks, such as
the manipuation the PortetPreferences object associated with the doEdit
mode, or forcing a portet to dispay itsef in a maximized state, simpy
can t be performed during the portet rendering phase. Such tasks must be
performed before a portet is asked to render itsef, during an important
stage known as the event processing or action processing phase. The
event processing phase is associated with a specia method caed
processAction. pubic void processAction (ActionRequest request,
ActionResponse response) throws PortetException, IOException {}
ActionRequest and ActionResponse You wi notice that the processAction
method is passed a request and response object that are different in
type to the request and response objects passed to the doView method.
The processAction method receives an ActionRequest and an ActionResponse
object, both of which inherit from PortetRequest and PortetResponse
respectivey, but provide action phase functionaity, as opposed to
rendering phase functionaity. Whie it is not a compier enforced rue,
tasks such as state management, session management, and form handing
shoud a be performed in the action processing phase of a portet. We have
cheated a bit in some of our exampes, just to keep our portets as simpe
as possibe, but as a genera rue, appication processing shoud occur in
the processAction method of a portet, not the doView method, as we have
seen. WindowState and PortetMode Changes To re-emphasize the point,
there are certain things that absoutey must be performed in the action
processing phase of a portet, and attempts to do otherwise wi fai. For
exampe, ony the ActionResponse object has methods such as setPortetMode
and setWindowState. If you want a portet to render itsef in a maximized
state, this decision must be made before the rendering phase of a portet
takes pace. If you want the portet you are working with to render in the
edit mode, or a custom config mode, when the portet is rendered, the
setPortetMode method must be invoked during the actionProcessing phase.
Session Management and Action Processing The PortetSession object can be
manipuated during the rendering phase of a portet, but it is not a good
idea. The SimpeSessionPortet from the previous chapter paced a variabe
in the APPICATION_SCOPE of the PortetSession, so that other portets in
the same appication coud access the variabe. However, there is no way to
determine the order in which the doView method of various portets
appearing on a porta page wi be invoked, and with our
SimpeSessionPortet, the doView method that manipuated the PortetSession
was invoked after other portets had read the common vaue paced in the
APPICATION_SCOPE. As a resut, two portets, on the same porta page,
reading the same variabe from the session, actuay ended up dispaying
different vaues. Sometimes, the correct vaue wi appear, but you simpy
can t be guaranteed which portet s doView method wi be invoked first,
and which wi be invoked second. The ActionResponse vs. the
RenderResponse Both the RenderResponse and ActionResponse inherit from
the PortetResponse, but ony the ActionResponse has methods that aow for
the manipuation of the PortetMode and the WindowState. The ActionRequest
vs. the RenderRequest Both the ActionRequest and the RenderRequest
inherit from the PortetRequest, athough as you can see from the diagram,
the ActionRequest defines infinitey more new methods than the
RenderRequest. J The Event Processing Phase Whie the action processing
phase aways precedes the portet rendering phase, the portets we deveop
do not automaticay take part in event processing. For a portet to take
part in the event processing phase, a cient must invoke the portet using
a specia actionUR, and the portet being invoked must impement the
processAction method. et s take a ook at portet that both impements the
processAction method, and triggers itsef using an actionUR. pubic cass
StateShifter extends GenericPortet { //portet rendering phase pubic void
doView (RenderRequest request, RenderResponse response) throws
PortetException, IOException {} //action processing phase pubic void
processAction (ActionRequest request, ActionResponse response) throws
PortetException, IOException {} } Working with the WindowState Object
The goa of this portet is to move the user from one portet state to
another. The various portet states are: maximized, minimized and norma.
To impement this state shifting, we use the WindowState object to
estabish the current state of the portet, and then use the
response.setWindowState() method to perform the change. The ogic of the
StateShifter Portet If the window is in the norma state, we wi switch to
the maximized state, and if the window is maximized, we wi re-render in
the minimized state. The code is reativey straight forward and readabe:
pubic void processAction """ WindowState state =
request.getWindowState(); if (state == WindowState.NORMA) {
response.setWindowState(WindowState.MAXIMIZED); } if (state ==
WindowState.MAXIMIZED) { response.setWindowState(WindowState.MINIMIZED);
} if (state == WindowState.MINIMIZED) {
response.setWindowState(WindowState.NORMA); } """
javax.portet.WindowState ?The WindowState cass represents the possibe
window states that a portet window can assume. This cass defines a
standard set of the most basic portet window states. Additiona window
states may be defined by caing the constructor of this cass. If a
porta/portet-container does not support a custom window state defined in
the portet appication depoyment descriptor, the custom window state wi
be ignored by the porta/portet container. ? -Description of the
WindowState from the IBM/Sun Porta API JavaDocs Custom Window States The
JSR-168 specification aows portas to define custom window states, such
as a pop-up state. If a portet tries to use a window state that is not
supported by the porta server, a WindowStateException wi be thrown.
Figure xxx-xxx This portet changes the WindowState when a user cicks on
an action ink package com.examscam.portet; import java.io.*; import
javax.portet.*; pubic cass StateShifter extends GenericPortet { pubic
void doView (RenderRequest request, RenderResponse response) throws
PortetException, IOException {
response.setContentType("text/htm"); PortetUR ur =
response.createActionUR(); ur.setParameter("shift",
"true"); PrintWriter out = response.getWriter();
out.print(" <A href=" + ur + ">State
Shift!!!</A> "); } pubic void processAction (ActionRequest
request, ActionResponse response) throws PortetException,
java.io.IOException { if (request.getParameter("shift") != nu)
{ WindowState state = request.getWindowState(); if (state ==
WindowState.NORMA) { response.setWindowState(WindowState.MAXIMIZED); }
if (state == WindowState.MAXIMIZED) {
response.setWindowState(WindowState.MINIMIZED); } if (state ==
WindowState.MINIMIZED) { response.setWindowState(WindowState.NORMA); } }
} } Moods of the StateShifter The StateShifter portet has three
different moods, corresponding to the three different WindowState
settings. The StateShifter starts off in a NORMA state, but when the
action ink State Shift is cicked, the portet renders itsef in the
MAXIMIZED state. When State Shift is cicked on a maximized StateShifter
portet, the action processing phase sets the WindowState to MINIMIZED.
In the MINIMIZED state, no content is visibe, so the restore or maximize
button on the portet must be cicked to change the WindowState to either
restore (set WindowState to NORMA) or maximize the portet. Triggering an
Action Coding the processAction method is the way to hande an action
event, but the processAction method wi never be caed if a cient never
actuay triggers an action. To trigger the action processing phase, an
action event must be generated. To trigger an action event, a user must
cick on a ink, or submit a form, that has an action expicity associated
with it. It s easy to create ink back to the porta that has an action
associated with it, athough it is a two step process. You simpy ask the
ActionRequest object to create an actionUR. We, there reay is not such
thing as an ActionUR, but instead, a PortetUR that is associated with an
action event. 1. PortetUR ur = response.createActionUR(); Once the
PortetUR is obtained, we can optionay add parameters to the PortetUR
that hep identify the action: 2. ur.setParameter("shift",
"true"); Finay, the PortetUR must be used in an HTM ink, or as
the action attribute of an htm form. We create an HTM anchor ink that a
user can cick on: PrintWriter out = response.getWriter();
out.print(" <A HREF=" + uri + "> State
Shift!!!</A> "); If a user cicks on the ink generated by the
code above, the event processing phase wi be triggered on the server,
and an action event associated with the String ?shift?, wi be passed to
the our portet. Encoding the attribute probaby woudn t be a bad idea
either, but it s been eft out for the sake of simpicity. pubic void
doView """ {
response.setContentType("text/htm"); PortetUR ur =
response.createActionUR(); PrintWriter out = response.getWriter();
out.print(" <A href=" + ur + ">State
Shift!!!</A> "); } """ Handing the Right Event
Object When an event is fired, we want our Portet to be abe to react to
the action, figure out exacty what action was triggered, and then
execute some type of ogic based on the event. In the doView method, a
parameter was appended to our PortetUR named ?shift . This parameter
named shift, is essentiay the name of our action event. pubic void
doView """ /*create an action UR associated with the vaue
shift*/ PortetUR ur = response.createActionUR();
ur.setParameter("shift", "true"); """
To make sure our portet ony responds to the shift action, and not
actions generated by other portets on the page, we extract the String
associated with the event from the ActionRequest object passed into the
processAction method. pubic void processAction """
/*check if the action was associated with shift*/ if
(request.getParameter("shift") != nu) { """ }
""" Depoyment Descriptor for the StateShifter <!--
portet.xm for the StateShifter portet --> <?xm
version="1.0" encoding="UTF-8"?> <portet-app
xmns="http://java.sun.com/xm/ns/portet/portet-app_1_0.xsd"
version="1.0"
xmns:xsi="http://www.w3.org/2001/XMSchema-instance"
xsi:schemaocation="http://java.sun.com/xm/ns/portet/portet-app_1_0.xsd
http://java.sun.com/xm/ns/portet/portet-app_1_0.xsd"
id="com.examscam.portet.StateShifter.9566e4bdf0">
<portet> <portet-name> StateShifter
<portet-name></portet-name> <dispay-name> StateShifter
<dispay-name></dispay-name> <dispay-name
xm:ang="en"> StateShifter
<dispay-name></dispay-name> <portet-cass>
com.examscam.portet.StateShifter <portet-cass></portet-cass>
<expiration-cache> 0
<expiration-cache></expiration-cache> <supports>
<mime-type> text/htm <mime-type></mime-type>
<portet-mode> view <portet-mode></portet-mode>
<supports></supports> <supported-ocae> en
<supported-ocae></supported-ocae> <portet-info>
<tite> StateShifter <tite></tite>
<portet-info></portet-info> <portet></portet>
<portet-app></portet-app> Revisiting the NumberGuesser
Portet Pease don t get mad at me for saying so, but our
NumberGuesserPortet vioated a number of best practices by handing forms,
and processing session state, within the render phase of the portet. A
better design woud be to move a of the processing into the action phase
of the portet, and eave rendering tasks to the doView method. Fig. X-xxx
shows the changes required to be made to the NumberGuesserPortet, aong
with the changes needed in the corresponding JSP to ensure the action
processing phase of the portet is triggered. Action Processing and
Custom Tags In previous iterations of the NumberGuesserPortet, we have
used the <portet:renderUR /> custom tag with the action attribute
of the HTM FORM tag. As you coud imagine, the renderUR tag sends a
request directy into the render phase of a portet, competey bypassing
the action processing phase. To ensure that the about to be created
action processing phase of the NumberGuesserPortet actuay gets invoked
when a user cicks on the submit button abeed Guess, we must repace the
od custom tag of <portet:renderUR /> with the custom tag that
triggers the action phase, namey the <portet:actionUR /> tag.
Figure 6-8xxx Using the <portet:actionUR /> Custom Tag <%@ page
contentType="text/htm"%> <%@ tagib
uri="http://java.sun.com/portet"
prefix="portet"%> <portet:defineObjects />
<%=renderRequest.getPortetSession().getAttribute("message")%>
<FORM action=""><portet:actionUR />"> I'm
thinking of a number between 1 and 10. <BR> <INPUT
name="number" size="10" type="text" />
<!-- The name of the input tag becomes very important -->
<INPUT name="guesssubmit" vaue="Guess!!"
type="submit" /></FORM> Number of guesses:
<%=renderRequest.getPortetSession().getAttribute("guesses")%>
Refactoring Actions into the NumberGuesser Much of the content that was
in the doView method of the NumberGuesserPortet has been moved to the
processAction method. When session management and form handing tasks
have been moved into the processAction method, the doView method
correcty is eft with itte more to do than forward to the appropriate JSP
page. Figure 6-7xxx Responding to Action Events package
com.examscam.portet; import java.io.*;import javax.portet.*; pubic cass
NumberGuesserPortet extends GenericPortet { protected void
doView(RenderRequest request, RenderResponse response) throws
PortetException, IOException { PortetContext context =
this.getPortetContext(); PortetSession session =
request.getPortetSession(); /*This iteration ooks for the message, not
the magicnumber*/ if (session.getAttribute("message") == nu) {
/*int magicNumber = (int)(System.currentTimeMiis() % 9) + 1;*/
/*session.setAttribute("magicnumber", new
Integer(magicNumber));*/ int magicNumber = (int)
(System.currentTimeMiis() % 9) + 1;
session.setAttribute("magicnumber", new Integer(magicNumber));
session.setAttribute("guesses", "0");
session.setAttribute("message", "Guess the
number!"); } String ur = "/numberguesser.jsp";
context.getRequestDispatcher(ur).incude(request, response); } pubic void
processAction(ActionRequest request, ActionResponse response) throws
PortetException, java.io.IOException { PortetSession session =
request.getPortetSession(); /*make sure name=?guesssubmit? is added to
the JSP!!!*/ if (request.getParameter("guesssubmit") != nu) {
if (session.getAttribute("magicnumber") == nu) { int
magicNumber = (int) (System.currentTimeMiis() % 9) + 1;
session.setAttribute("magicnumber", new Integer(magicNumber));
session.setAttribute("guesses", "0"); } Integer
magicNumber=(Integer)session.getAttribute("magicnumber");
String guesses = (String) session.getAttribute("guesses");
guesses = "" + (Integer.parseInt(guesses) + 1);
session.setAttribute("guesses", guesses);
session.setAttribute("message", "Guess higher!");
Integer guess = new Integer(request.getParameter("number"));
if (guess.intVaue() > magicNumber.intVaue()) {
session.setAttribute("message", "Guess ower!"); } if
(guess.intVaue() == magicNumber.intVaue()) { String message =
magicNumber + " is correct. Pay again!";
session.setAttribute("message", message);
session.removeAttribute("magicnumber"); } } } } Comparison
with and without processAction Figure xxx and Figure xxx contain the
code for the NumberGuesserPortet with xxx using the action processing
phase, and xxx not taking advantage of action processing. When comparing
them, you can see that the ogic is, for the most part, simiar, but the
division of tasks, namey state management and view processing, is more
eegant when using the action processing phase. Figure 6-7xxx Responding
to Action Events package com.examscam.portet; import java.io.*;import
javax.portet.*; pubic cass NumberGuesserPortet extends GenericPortet {
protected void doView(RenderRequest request, RenderResponse response)
throws PortetException, IOException { PortetContext context =
this.getPortetContext(); PortetSession session =
request.getPortetSession(); /*This iteration ooks for the message in the
session*/ if (session.getAttribute("message") == nu) { /*int
magicNumber = (int)(System.currentTimeMiis() % 9) + 1;*/
/*session.setAttribute("magicnumber", new
Integer(magicNumber));*/ session.setAttribute("guesses",
"0"); session.setAttribute("message", "Guess
the number!"); } String ur = "/numberguesser.jsp";
context.getRequestDispatcher(ur).incude(request, response); } pubic void
processAction(ActionRequest request, ActionResponse response) throws
PortetException, java.io.IOException { PortetSession session =
request.getPortetSession(); if
(request.getParameter("guesssubmit") != nu) { if
(session.getAttribute("magicnumber") == nu) { int magicNumber
= (int) (System.currentTimeMiis() % 9) + 1;
session.setAttribute("magicnumber", new Integer(magicNumber));
session.setAttribute("guesses", "0"); } Integer
magicNumber=(Integer)session.getAttribute("magicnumber");
String guesses = (String) session.getAttribute("guesses");
guesses = "" + (Integer.parseInt(guesses) + 1);
session.setAttribute("guesses", guesses);
session.setAttribute("message", "Guess higher!");
Integer guess = new Integer(request.getParameter("number"));
if (guess.intVaue() > magicNumber.intVaue()) {
session.setAttribute("message", "Guess ower!"); } if
(guess.intVaue() == magicNumber.intVaue()) { String message =
magicNumber + " is correct. Pay again!";
session.setAttribute("message", message);
session.removeAttribute("magicnumber"); } } } }
NumberGuesserPortet without ProcessAction As you can see, the content of
the processAction method was pretty much ifted directy from the ese bock
of the portet defined in Figure xxx. Figure 6-2xxx Previous Iteration of
NumberGuesserPortet package com.examscam.portet; import java.io.*;import
javax.portet.*; pubic cass NumberGuesserPortet extends GenericPortet {
protected void doView (RenderRequest request, RenderResponse response)
throws PortetException, IOException { PortetContext context =
this.getPortetContext(); PortetSession session =
request.getPortetSession(); if
(session.getAttribute("magicnumber") == nu) { int magicNumber
= (int) (System.currentTimeMiis() % 9) + 1;
session.setAttribute("magicnumber", new Integer(magicNumber));
session.setAttribute("guesses", "0");
session.setAttribute("message", "Guess the
number!"); } ese { Integer magicNumber = (Integer)
session.getAttribute("magicnumber"); String guesses = (String)
session.getAttribute("guesses"); guesses = "" +
(Integer.parseInt(guesses) + 1);
session.setAttribute("guesses", guesses); Integer guess = new
Integer(request.getParameter("number")); if (guess.intVaue()
> magicNumber.intVaue()) { session.setAttribute("message",
"Guess ower!"); } ese {
session.setAttribute("message", "Guess higher!"); }
if (guess.intVaue() == magicNumber.intVaue()) { String message =
magicNumber + " is correct. Pay again!";
session.setAttribute("message", message);
session.removeAttribute("magicnumber"); } } String ur =
"/numberguesser.jsp";
context.getRequestDispatcher(ur).incude(request, response); } } Question
6-1 If a portet attempts to transition to a custom portet state that is
not supported by the porta server: a) the portet wi throw a
ServetException b) the portet wi throw a WindowStateException c) the
portet wi throw a ServetError d) the portet wi throw a WindowStateError
Question 6-2 Which of the foowing methods are not defined in the
ActionResponse cass? a) setWindowState(state:WindowState) b)
sendRedirect(ur: String) c) setTite(tite:String) d) getWriter() Answer
6-3 The processAction method a) is invoked before every doView method b)
is invoked ony if a cient cas the portet using an actionUR c) is foowed
by a the rendering phase of a portet d) is preceded by the rendering
phase of a portet. Question 6-4 To participate in the action processing
phase, a portet: a) must have action processing configured in the
portet.xm fie b) must define a processAction method c) must define an
actionPerformed method d) must be invoked through an action UR Question
6-5 Which of the foowing are not possibe during the render processing
phase? a) changing the portet mode b) changing the portet window state
c) accessing the PrintWriter d) accessing data in the PortetSession
Answer 6-6 If a PortetException is thrown during the action processing
phase of a portet, which of the foowing is true a) instructions to
render the portet in a Maximized window wi be ignored b) instructions to
render the portet in the edit mode wi be ignored c) other portets on the
page wi be forced to stop their rendering process d) other portets on
the page wi continue the rendering process Answer xxx-1 If a portet
attempts to transition to a custom portet state that is not supported by
the porta server: a) the portet wi throw a ServetException b) the portet
wi throw a WindowStateException c) the portet wi throw a ServetError d)
the portet wi throw a WindowStateError Option b) is correct. The
WindowStateException just hides in the outskirts quiety, minding its own
business, just waiting for a portet to ask for a WindowState other than
MINIMIZED, MAXIMIZED or NORMA. If it sees an unsupported WindowState
being requested, it jumps, and triggers the exception handing features
of the portet. Answer 6-2 Which of the foowing methods are not defined
in the ActionResponse cass? a) setWindowState(state:WindowState) b)
sendRedirect(ur: String) c) setTite(tite:String) d) getWriter() Options
c) and d) are correct. The ActionRequest has the abiity to redirect, or
set the WindowState. However, accessing the PrintWriter, and changing
the portet tite dispayed to the user, is purey part of the rendering
phase of the porta. Answer 6-3 The processAction method a) is invoked
before every doView method b) is invoked ony if a cient cas the portet
using an actionUR c) is foowed by a the rendering phase of a portet d)
is preceded by the rendering phase of a portet. Answers b) and c) are
correct. The processAction method is not invoked on every singe
request-response cyce the portet takes part in, but instead, ony during
the request response cyces in which the cient has used an actionUR, as
opposed to a renderUR. Aso, so ong as an exception doesn t mess the
action processing stage up, the rendering phase foows the action
processing phase. The rendering phase wi never come before the action
processing phase of a portet. Answer 6-4 To participate in the action
processing phase, a JSR-168 portet: a) must have action processing
configured in the portet.xm fie b) must define a processAction method c)
must define an actionPerformed method d) must be invoked through an
action UR Options b) and d) are correct. There is no xm configurations
that need to be made for a portet to take part in action processing. A a
portet needs to do is code the processAction method, and subsequenty be
invoked through an action UR. The actionPerform method was coded in the
egacy portet API, but not in JSR-168. Answer 6-5 Which of the foowing
are not possibe during the render processing phase? a) changing the
portet mode b) changing the portet window state c) accessing the
PrintWriter d) accessing data in the PortetSession Options a) and b) are
correct. Whie the render processing phase actuay spits content out to
the user, it is reay the action processing phase that decides big
picture things, ike the portet mode, or the portet state. Aternativey,
the PrintWriter cannot be accessed during the rendering phase. The
PortetSession is avaiabe in both the action processing, and rendering
phase of the portet. Answer 6-10 xxxx If a PortetException is thrown
during the action processing phase of a portet, which of the foowing is
true a) instructions to render the portet in a Maximized window wi be
ignored b) instructions to render the portet in the edit mode wi be
ignored c) other portets on the page wi be forced to stop their
rendering process d) other portets on the page wi continue the rendering
process Options a) b) and d) are a correct. If a PortetException is
thrown during the action processing phase, a operations performed on the
ActionResponse must be ignored, and this incudes maximizing the window,
or dispaying in the edit mode. However, just because one portet messes
up in the action phase, doesn t mean the other portets on the page shoud
suffer. Other portets wi be aowed to render normay, making d) correct as
we.