Learn Logo
Home    |    www.ExamScam.com    |    Leave Us A Message    |    SCJA Java Certification Site    |    Free Mock Cert Exams    |    Free Multimedia Tutorials   

pulpJavaNetwork


Support this site!
(And bill it to your boss)

Buy it now on Amazon!



Search Now:
Google

State Management and the PortletSession

 

If the user is going to be kind enough to provide information to us through html forms and http headers, the least we could do is keep track of that information, if only for the duration of the users visit to our site.

 

To provide a stateful experience for the portal user, portlet developers rely upon the services of the PortletSession, an object that is remarkably similar to the HttpSession object from the Servlet API.

 

The PortletSession is easy to use, and helps maintain a stateful experience for the user.

 

This chapter will look at the PortletSession, how the PortletSession works, and will even discuss some of the drawbacks and alternatives to using the PortletSession object.

 

The Transient Nature of the PortletSession

PortletSessions and User Portlets

Leveraging the PortletSession Object

The NumberGuesser and the PortletSession

Tips for Manipulating Objects Stored in the PortletSession

Inspecting the BettetNumberGuesser Portlet

When Form Data is Absent

Session Management When Form Data is Present

Always Remove Unneeded Data from the PortletSession

Debriefing the BetterNumberGuesser’s JSP Pages

Using the PortletRequest Scope

A Word About the PortletRequest Object

Multiple Scopes Exist for Passing JavaBeans Around

The PortletRequest Object is the Most Efficient Scope

Using PortletSession in the betternumberform.jsp

Cleverly Using the <portletAPI:createURI/> Custom Tag

Ending the Number Guessing Game

The correct.jsp

The State Management Challenge

The Unsexy PortletUnavailable Error Message

The Blight of Non-Standard User Navigations


Managing State with the PortletSession Object

When a user visits our site, we quite often need to keep track of information the user has provided us. Information stored in the PortletRequest or PortletResponse object are purged as soon as a response is sent back to the client, which creates a problem when we want to keep track of information that a user has provided us on previous request-response cycles.

To store user specific information for the duration of their interaction with the server, the Portal API provides a special object called the PortletSession.

Any useful piece of information, in the form of serializable Java objects that is, can be stuffed inside of a user’s session object. That information is then available to our portlet on all subsequent request-response cycles. The PortletSession is effectively tied to the user for which it was created.

The Transient Nature of the PortletSession

One thing to note about the PortletSession is that it is transient. If the user leaves our site, doesn’t interact with the site for a predetermined amount of time (usually thirty minutes), or even if the user closes their browser, information stored in the PortletSession is lost, or at least, is no longer tied to the user.

Information stored in the PortletSession is not stored persistently. The job of the PortletSession is to simply create a stateful experience for users interacting with our portlet during the current visit to our website.

PortletSessions and User Portlets

Another interesting aspect of a PortletSession is that it is local to the portlet that created it. Data stored in the PortletSession of one portlet cannot be shared by other portlets on the same portal page. If there are four portlets on a portal page, if they all use a PortletSession object, then each one will have a separate, unshared PortletSession.

Many developers believe that data stored in the PortletSession is available to all the portlets a user might access. This is not true. A PortletSession is tied to the specific portlet on the specific portal page for which the PortletSession was created.


Leveraging the PortletSession Object

Here’s a simple portlet that keeps track of the number of times the doView method of a portlet is called.

The view count is stored in the session. Every time the doView method of the portlet is called, the view count increases by one. The view count is then displayed back to the user.

 

Figure ?-?

package com.pulpjava.example.session;

import java.io.*;import org.apache.jetspeed.portlet.*;

 

public class SessionSample extends PortletAdapter {

  public void doView(PortletRequest request, PortletResponse response)

                                                     throws PortletException, IOException {

    //grab the PortletSession out of the PortletRequest

    PortletSession session = request.getPortletSession();

    //pull the visitCount out of the session. On the first visit, this will be null

    String visitCount = (String)session.getAttribute("timesvisited");

    PrintWriter out = response.getWriter();

 

    //if this is the first time viewing the portlet, set the timevisited value to 1

    if (visitCount==null){

      session.setAttribute("timesvisited", ""+1);

      out.print("Wecome to our little portlet!");

      out.print("<BR>Click refresh, restore, minimize or maximize!!!");

    }

    //if this portlet has been visited before, increase the count

    else {

      int newCount = Integer.parseInt(visitCount) + 1;

      session.setAttribute("timesvisited", "" + newCount);

      out.print("Number of times visiting this portlet: ");

      out.print(newCount);

    }

  }

}


The NumberGuesser and the PortletSession

Our NumberGuesserPortlet could really use a good dose of the PortletSession object.

Currently, our NumberGuesserPortlet, from figure ?-?, thinks of a number, and asks the user to guess it, but it doesn’t give the user a chance to keep trying until they guess the magic number.

By incorporating the PortletSession object into the NumberGuesserPortlet, we could store both the magic number and the number of guessing attempts. We could even give the user a hint as to whether they should guess higher or lower.

When the user guesses the magic number successfully, we can even send them to a JSP page that indicates that they have successfully guessed the magic number, and displays the number of attempts it took.

Our improved NumberGuesserPortlet appear in Figure ?-?

Tips for Manipulating Objects Stored in the PortletSession

Information is pulled out of the PortletSession using the getAttribute(String) method. Objects are put into the PortletSesison object using the setAttribute(String, Object) method.

The name used to put an object into the session must match exactly the name used to pull the object out. Spelling mistakes, or even a different casing of letters will cause the return of a null object. I always suggest using all lower case letters for the names of objects being placed into the session, if only to create a consistent standard.

The PortletSession also includes a method called removeAttribute(Object). If you no longer have use for an object you have stored in the PortletSession, that object should be removed from the session.

The management of session data is one of the most significant performance bottlenecks your portal server will encounter. Eliminate unnecessary objects from your PortletSession, and trying to avoid what is known as ‘session bloat’ will help minimize performance problems at runtime.


Figure ?-?  We can easily as PortletSession support to our NumberGuesser

package com.pulpjava.betterguesser;

import java.io.IOException;  import org.apache.jetspeed.portlet.*;


public class BetterNumberGuesser extends PortletAdapter {

  public void doView(PortletRequest request, PortletResponse response)

                                                     throws PortletException, IOException {  

    PortletContext context = getPortletConfig().getContext();

    PortletSession session = request.getPortletSession();

 

    if (request.getParameter("number") == null) {

      int magicNumber = (int)(System.currentTimeMillis() % 9) + 1;

      session.setAttribute("magicnumber", new Integer(magicNumber));

      session.setAttribute("guesses", "0");

      request.setAttribute("message", "Guess the number!");

      context.include("betternumberform.jsp", request, response);

 

    } else {

      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.intValue() > magicNumber.intValue()) {

        request.setAttribute("message", "Guess lower!");

        context.include("betternumberform.jsp", request, response);

      }

      if (guess.intValue() < magicNumber.intValue()) {

        request.setAttribute("message", "Guess higher!");

        context.include("betternumberform.jsp", request, response);

      }

      if (guess.intValue() == magicNumber.intValue()) {

         session.removeAttribute("guesses");

         session.removeAttribute("magicnumber");

      }

    }

  }

}


Inspecting the BettetNumberGuesser Portlet

When Form Data is Absent

The first two lines of the BetterNumberGuesser portlet simply declares the PortletSession and PortletContext object for easy access later on in the code.

The next step is to see if form data is indeed coming to the server. If there is no form data submitted, then we can assume the user is looking at this portlet for the first time, or they are re-starting the guessing process. In that case, we create a new magic number and stuff that number into the PortletSession. We also set the number of guesses to zero, after all, the number guessing process is just starting.

Once all of our objects have been initialized and stuffed into the PortletSession, we can forward to the betternumberform.jsp page, but before we do that, we stuff a little message into the PortletRequest. The message simply says “Guess the number!!!” This message will be printed out by the JSP.

 


Figure ?-?

 

"""
public class BetterNumberGuesser extends PortletAdapter {

"""

 

    if (request.getParameter("number") == null) {

 

      int magicNumber = (int)(System.currentTimeMillis() % 9) + 1;

      session.setAttribute("magicnumber", new Integer(magicNumber));

      session.setAttribute("guesses", "0");

      request.setAttribute("message", "Guess the number!");

      context.include("betternumberform.jsp", request, response);

 

    } else {

"""

}

 


Session Management When Form Data is Present

If request.getParameter(“number”) does not return null, then indeed the user has just submitted a form, trying to guess the magic number. In this case, we grab our magic number from the session, then we grab the number of guesses from the session, and finally we grab the actual number guessed by calling the request.getParameter(“number”) method.

If the number is too high, we send them to the betternumberform.jsp file with a message stuffed into the request object instructing them to guess lower.

request.setAttribute("message", "Guess lower!");

If the number is too low, we send them to the betternumberform.jsp file with a message stuffed into the request object instructing them to guess higher.

request.setAttribute("message", "Guess higher!");

If the user guesses the magic number correctly, we delegate to the correct.jsp, which indicates that the user has successfully guessed the magic number.

Always Remove Unneeded Data from the PortletSession

After rendering the correct.jsp, we also remove the magic number and the number of guesses from the session. After all, they are not needed once the magic number has been guessed. If the user wants to play again, we’ll just generate a new number, and set their number of guesses to zero.

 


Figure ?-?

 

"""

if (guess.intValue() == magicNumber.intValue()) {

   context.include("correct.jsp", request, response);

   session.removeAttribute("guesses");

   session.removeAttribute("magicnumber");
}

"""

 

Debriefing the BetterNumberGuesser’s JSP Pages

There are two JSP pages used in this example, the betternumberform.jsp, and the correct.jsp. Let’s look at the betternumberform.jsp page.

 


Figure ?-?

 

<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %>

<portletAPI:init />

 

<FORM action="<portletAPI:createURI/>">

 

I'm thinking of a number between 1 and 10.<BR><BR>

<I><%=request.getAttribute("message")%></I>

 

<INPUT name="<portletAPI:encodeNamespace

                                                  value="number"/>" size="10" type="text" />

<INPUT name="<portletAPI:encodeNamespace value="submit"/>"

                                                                  value="Guess!!" type="submit" />

</FORM>

 

Number of guesses: <%=session.getAttribute("guesses")%><BR>

 

<A HREF="<portletAPI:createURI/>">Start Over</A>

 

Using the PortletRequest Scope

The biggest change between new betternumberguesserform.jsp and the one used earlier in figure ?-?,  is the presence of the <%=request.getAttribute(“message”)%> expression just before the input field.

Inside the BetterNumberGuesser portlet, a String message is placed in the request scope, indicating whether a user should guess higher or lower. This message is then printed out just before the textfield in the betternumberguesser.jsp page. This scriptlet allows one JSP page to be used dynamically, and render itself slightly differently depending upon the state of the application.

 

A Word About the PortletRequest Object

While the PortletRequest’s main purpose in life is to describe the incoming request, it can be also used to pass information from a portlet to a JSP, or from one JSP to another JSP.

Multiple Scopes Exist for Passing JavaBeans Around

Just as we can store Java objects in a user’s PortletSession, we can store Java objects in the PortletRequest as well. In fact, the process is so similar, the methods for storing attributes in the PortletSession and the PortletRequest are the same:

portletRequest.setAttribute(String key, Object value);
portletSession.setAttribute(String key, Object value);

The PortletRequest Object is the Most Efficient Scope

The big difference between the PortletRequest and PortletSession as a means for passing data between a Servlet and a JSP is the duration of the data stored. Information stuffed into a PortletSession will last as long as the user remains at our site, whereas data shoved into a PortletRequest is purged as soon as a response is sent back to the client; or more accurately, once the service method of the Portlet has finished execution.

The PortletRequest is the perfect scope to use when you want to share a Java object between a portlet and JSP, but you don’t want that data to hang around beyond the current request-response cycle, as it would if it was stored in the PortletSession.

Use the PortletRequest scope. It’s memory efficient and resource-friendly.


 

Using PortletSession in the betternumberform.jsp

Our improved html form from our betternumberform.jsp also displays to the user how many guesses they have made at the magic number, based on the ‘guesses’ key placed in the PortletSession during the doView method.

Number of guesses: <%=session.getAttribute("guesses")%>

Finally, our improved form provides a link for the user to start the number guessing game over again.

<A HREF="<portletAPI:createURI/>">Start Over</A>

Notice how we are again using the portletAPI:createURI custom tag, but this time the tag is used to create an anchor link, rather than specifying an action target for a form.

Cleverly Using the <portletAPI:createURI/> Custom Tag

This use of the portletAPI:createURI custom tag will create a link in the portlet that when clicked, will cause the portal page to re-render itself. Of course, since it was a link that triggered the page to be displayed, and not a form submission, the doView method will reset the number of guesses to zero, and generate a new magic number, since no guessed number will be sent to the server. Pretty clever, eh?


Ending the Number Guessing Game

The correct.jsp file compliments our improved form, and represents the end of the number guessing game.

 


Figure ?-? The correct.jsp

 

<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %>

<portletAPI:init />

 

You got it correct!

<BR><BR>

 

The magic number was <%=session.getAttribute("magicnumber")%>

<BR><BR>


Number of guesses: <%=session.getAttribute("guesses")%>

<BR><BR>


Click <A HREF="<portletAPI:createURI/>">here</A> to start over.

 

The correct.jsp

The correct.jsp page simply displays a congratulatory ‘You got it correct!’ message, and then displays the magic number, along with the number of attempts it took for the user to come up with the correct answer.

A link back to the portlet is also used to allow the user to play the number guessing game again.


The State Management Challenge

NOTE: When the number guessing portlet is completed, if you refresh the page, you will get an error. This is due to the fact that a refresh causes previously submitted forms to be resubmitted.

The Unsexy PortletUnavailable Error Message

Of course, when our game is completed, the magic number is pulled out of the session. This will trigger a doView method that has form data, but does not have the number of guesses, or a magic number. Either of the following two lines:

Integer.parseInt(guesses)
magicNumber.intValue()

will trigger a null pointer exception, causing a ‘Portlet Unavailable’ message to be delivered back to the user.

To avoid this problem, our doView method should not only check for form data, but also check to make sure the magicnumber key in the PortletSession object is not null.

A more robust beginning to our portlet might look like this:

 

Object formData = request.getParameter("number");

Object sessionData = session.getAttribute("guesses");

if (formData==null || sessionData==null) {…..}

 

The Blight of Non-Standard User Navigations

The portal provides many opportunities for non-standard navigations by the user, perhaps even more than a typical Servlet and JSP application allows. We must be aware of all of these non-standard navigations, and do our best to create robust portlets that do not fail when a user does unexpected things.

Never doubt this truism: as idiot-proof as we make our application, the world will keep creating better idiots. Thoroughly test your applications for non-standard user navigations.

 

Home    |    www.ExamScam.com    |    Leave Us A Message    |    SCJA Java Certification Site    |    Free Mock Cert Exams    |    Free Multimedia Tutorials   
sbs
eXTReMe Tracker