portlets and the request-response cycle
At the most fundamental level, portlets are simply
presentation components that handle a request and response cycle.
When a request comes in from a client, portlets are
responsible for inspecting that request, and figuring out exactly what the
client is requesting.
Once the portlet has figured out what the crazy client is requesting, the
portlet must then figure out how to respond. Before responding to a client, a
portlet might use a bunch of EJBs or JavaBeans, but eventually, a response must
be formed and sent back to the client.
The essence of portlet programming is handling the
request-response cycle. Conquer the request response cycle, and the rest of the
portlet API will easily fall under your control.
The
PortletRequest and the PortletResponse
The
PortletRequest Object
The
PortletResponse Object
Looking at a
Simple Portlet
The
PortletAdapter Class
The View Mode and
the doView Method
The
PortletRequest Object
The
PortletResponse Object
Things You
Shouldn’t Do with the PortletResponse
Discourage Redirects
and Error Codes
Inspecting
Headers
Debriefing the
HeaderPortlet
When You Know the
Header Name of Interest
Headers and other
Enumerable Elements
The Enumeration
Class is Infinitely Reusable
Portlets and the Request-Response Cycle
In the most basic sense, a portlet simply handles a web based,
request-response cycle. As a Portlet developer, our fundamental responsibility
is to simply inspect the incoming request and subsequently supply an
appropriate response back to the user.
The portlet API makes it very easy to develop delicious portlets
that can intelligently respond to this web based request-response cycle. To
create a portlet that can be viewed on any portal page, we simply create a Java
class that extends PortletAdapter, and code a special method called doView.
And what do we do in the doView method? We implement some logic
and eventually send some output to the client. The junk we ouput appears within
the confines of a portlet on a portal page.
|
Figure 1-1
Output generated in the doView method is rendered
within the confines of a portlet.
|
|
The PortletRequest and the PortletResponse
Two supremely important objects are passed to a portlet’s doView
method:
>>> the PortletRequest object
>>> the PortletResponse object
The PortletRequest Object
Everything a developer wants to know about the incoming request
is stuffed inside the PortletRequest object. Anything a developer wants to do
to the client is done through the PortletResponse object.
Okay, maybe a developer can’t slap an annoying end user across
the face with the PortletResponse object, but they can send them html or an
error message. Planting a tasty cookie on a client machine, or even sending
back a cache directive can be done through the response object.
The PortletResponse Object
Anything a developer wants to know about the incoming request is
bundled up inside of the PortletRequest. Anything a developer is allowed
to do to the client is done through the PortletResponse object. Conquer the
request and response objects, and you’ve conquered portlet programming. Portlet
programming is just that simple.
Of course, you don’t have to limit your portlets to simple
request-response programming. Few developers do. Java programming is all about
freedom, and you are free to make your portlets as complex as you want.
Fundamentally though, all portlet development can be broken down
to inspecting the incoming PortletRequest, implementing some funky logic, and
then using the PortletResponse to deliver an appropriate reply back to the
user. How you leverage the various services provided to you through the J2EE
compliant application server is up to you.
Looking at a Simple Portlet
Here’s a simple, yet highly cosmopolitan portlet that determines
a user’s preferred language, and prints out an undiscriminating message.
|
Figure ?-?a
Output generated in the doView method is rendered
within the confines of a portlet.
|
|
package com.pulpjava.snooper;
import java.io.IOException; import org.apache.jetspeed.portlet.*;
public class
CountrySnooperPortlet extends PortletAdapter {
public void doView(PortletRequest
request, PortletResponse
response)
throws PortletException, IOException
{
//use the PortletRequest to figure out
the user’s preferred language
String language = request.getLocale().getDisplayLanguage();
//use the PortletResponse to generate output for the portlet
response.getWriter().print("We love
people who speak ");
response.getWriter().print(language);
response.getWriter().print("!");
}
}
|
|
Figure ?-?b
Rendering of the above CountrySnooperPortlet
|
|
Notice how a method of the PortletRequest is used to find
information about the user’s country of origin.
Also notice how the PortletResponse provides access to a
PrintWriter that allows us to send content, in the form of html, back to the
user.
Anything you want to know about the client is in the request, and
anything you want to do to the client is done through the response.
The PortletAdapter Class
Portlets are Portlets because they extend a class called
PortletAdapter. PortletAdapter defines all of the important portlet methods
such as doView and doEdit, while at the same time extending the ever so
important org.apache.jetspeed.portlet.Portlet class.
|
Figure ?-?
The ancestry and the implemented interfaces of a
custom portlet.
|
|
If you dig a little deeper into the ancestry of the
PortletAdapter class, you will find the HttpServlet and the GenericServlet
classes. Fundametally, a portlet, as it runs on the WebSphere Application
Server, is simply a servlet with a few salacious tweakings.
public
class CountrySnooperPortlet extends PortletAdapter
Our custom portlet, from figure ?-?, named CountrySnooperPortlet,
states explicitly in its class declaration that it inherits from the
PortletAdapter class. Implied from this extension is the fact that the
CountrySnooperPortlet also inherits from Portlet, HttpServlet, GenericServlet,
and all of the other ancestors and implemented interfaces of the PortletAdapter
class.
The View Mode and the doView Method
The portlets that developers create can have all sorts of funky
methods coded into them, but there is one affable method that all custom
portlets must contain: the doView method.
When a portlet is initially displayed on a page, it is said to be
in ‘view mode.’ The view mode represents the normal way that a portlet looks
when it appears on a page.
The doView method of a portlet corresponds to the view mode of a
portlet. The way that a portlet, in its normal mode, should look on a page, is
coded into the doView method.
Since it must be possible to view a portlet on a page,
every portlet must have a doView method.
public void doView
(PortletRequest request, PortletResponse response)
throws PortletException,
IOException
The doView method of a portlet is fed the PortletRequest and
PortletResponse objects, and also throws the intolerable PortletException and
IOException.
A portlet can actually have up to four different modes, which
correspond to matching do<mode> methods. The four portlet view modes and
their matching methods include:
>>> View mode, corresponding to doView(…)
>>> Edit mode, corresponding to doEdit(…)
>>> Configure mode, corresponding todoConfigure(…)
>>> Help mode, corresponding to a doHelp(…)
While a portlet can implement any combination of these modes,
only the view mode is absolutely required.
The PortletRequest Object
A portlet’s primary responsibility is to handle a web based
request-response cycle. Information about the incoming client request is
encapsulated and passed to the do<mode> method in the form of a
PortletRequest object.
Any information a developer is allowed to know about the incoming
client request is obtained through the PortletRequest.
In the case of our CountrySnooperPortlet, we obtain the Locale
object from the request, allowing us to figure out the country from which the
request is coming.
Other pejorative things we can find out about the user through
the PortletRequest object include:
>>> The preferred language of the user
>>> Any headers served up by a client’s browser
>>> What a user typed into a textfield
>>> Which radio button a user selected
>>> The type of browser the client is using
>>> The color of the shirt the user is wearing
Okay, maybe the PortletRequest can’t tell you the color of the
shirt your user is wearing, but it can tell you practically anything else. With
the PortletRequest object, you can pretend you’re Sipowicz and interrogate the
incoming request all day long.
Table ?-?
|
Methods of the
PortletRequest: Return Type
|
|
getCookies( ): Cookies[ ]
|
getMode( ): Portlet.Mode
|
|
getLocale( ): Locale
|
isSecure( ): boolean
|
|
getHeader( ): String
|
getData( ): PortletData
|
The PortletResponse Object
While the PortletRequest is used to discover information about
the incoming request, the PortletResponse object is typically used to send
something back, or do something to, the client.
In the case of our CountrySnooperPortlet, figure ?-?, a
PrintWriter is obtained from the PortletResponse object through the call response.getWriter(),
allowing us to send html back to the client.
Other juicy things we can do to with a PortletResponse object
include:
>>> Plant a cookie on the client machine
>>> Send back a name value pair as a response header
>>> Create a link back to the current portlet
Things You Shouldn’t Do with the
PortletResponse
It should also be noted that only an html snippet is sent back to
the client through a do<mode> method (doView, doEdit, doConfig and
doHelp).
A portlet should never print out <HTML> or <BODY>
tags. The portal server takes care of the overall page layout through a theme.
The job of a Portlet is to simply render a snipped of markup language that will
be displayed in a predefined quadrant of the overall portal page.
Furthermore, any html tags that are opened in a portlet should be
closed in a portlet. Make sure your content snippet is well formed, and doesn’t
leave any dangling html tags, such as <TABLE> tags that don’t have a
matching </TABLE> tag.
Discourage Redirects and Error Codes
You should also avoid sending error codes back to the client
using the PortletResponse object, and never use the PortletResponse to redirect
a user to a completely different web page.
Those types of activities are fine in a regular JSP and Servlet program,
but a portlet should always deliver some type of content that can be rendered
in a portlet window.
Inspecting Headers
Much of the charitable information that comes to the server about
the client comes in the form of http headers. Headers, which arrive in the form
of name-value pairs, represent information that a web browser surreptitiously
sends to the server on every client request.
Using the Portal API, some creative use of the Enumeration class,
and a little Haitian Voodoo sprinkled in for good measure, looping through http
headers and seeing what type of data is being sent to the server is very easy
to do. Here’s a Portlet that does just that:
|
Figure ?-?
The following portlet loops through the various
headers sent to the server, and outputs the corresponding name-value pairs
within a portlet.
|
|
package
com.pulpjava.header;
import
java.io.*; import java.util.*;
import
org.apache.jetspeed.portlet.*;
public class
HeaderPortlet extends PortletAdapter {
public void doView(PortletRequest request,
PortletResponse response)
throws PortletException, IOException {
Enumeration enum =
request.getHeaderNames();
PrintWriter out = response.getWriter();
out.print("<B>The following
headers were sent to the server:</B><BR/> ");
while (enum.hasMoreElements()){
String name =
enum.nextElement().toString();
String value =
request.getHeader(name);
out.print("<BR/>");
out.print(name + ": " + value);
}
}
}
|
Debriefing the HeaderPortlet
Taking the time to try and understand exactly how the
HeaderPortlet works will pay off dividends in the future. Code that loops
through an enumeration of names and then accesses corresponding values will
come up time and time again, not only in this book, but in day to day portlet
and servlet based programming.
The first line of code in the doView method asks the request
object to return all of the various header names in the form of a very
congenial collection class called an Enumeration.
java.util.Enumeration
enum = request.getHeaderNames();
Once we have all of the header names in the enumeration, we can
move through the collection of names one at a time, using the hasMoreElements(
) method of the Enumeration class.
while
(enum.hasMoreElements( )) { //do something within these braces }
As we loop through the enumeration of header names, we can use
the nextElement( ) method of the Enumeration class to grab the each header
name, one at a time.
String
name = enum.nextElement( );
Once we have the name of the header, we can grab the actual value
of the header associated with that name.
String value =
request.getHeader(name);
When You Know the Header Name of
Interest
Of course, if we knew the name of a header of interest, we could
name it explicitly. For example, ‘user-agent’ is a the name of a header that
tells you information about the type of web browser a client is using. We could
grab the value associated with the user-agent header by making the following
method call:
String
browser = request.getHeader(“user-agent”);
The above line of code would return the following: (compatible;
MSIE 6.0; Windows NT 5.0 )
Headers and other Enumerable Elements
The results of our completed HeaderPortlet is a portlet that
lists all the header names and corresponding values that are sent to a web
server from a web based client.
The header names sent from a client to a web server include:
accept, referrer, accept-language, user-agent, host, connection and
cache-control. Different browsers and device types will send a different set of
headers, so the listing will vary from one client to another. Figure ?-? shows
the values associated with these various header names.
|
Figure ?-?
The rendering of the HeaderPortlet from Figure ?-?
|
|
The Enumeration Class is Infinitely
Reusable
Many objects in both the Servlet and Portlet API return a listing
of names as an enumeration, which can be looped through by using code very
similar to that that in our HeaderPortlet. Some of those enumerable objects
include:
>>> Objects placed in PortletData
>>> Initialization Strings stored in the PortletContext
>>> Objects placed in the PortletSession
>>> Data stored in the the PortletSettings object