views:

79

answers:

2

My session objects are only stored within the request scope on google app engine and I can't figure out how to persist objects between requests. The docs are next to useless on this matter and I can't find anyone who's experienced a similar problem. Please help.

When I store session objects in the servlet and forward the request to a JSP using:

getServletContext().getRequestDispatcher("/example.jsp").forward(request,response);

Everything works like it should. But when I store objects to the session and redirect the request using:

response.sendRedirect("/example/url");

The session objects are lost to the ether. In fact when I dump session key/value pairs on new requests there is absolutely nothing, session objects only appear within the request scope of servlets which create session objects. It appears to me that the objects are not being written to Memcache or Datastore. Its worth mentioning that everything works fine on my development server but when I upload to App Engine it breaks. This leads me to believe that it is a problem with configuration.

In terms of configuring sessions for my application I have set

<sessions-enabled>true</sessions-enabled>

In appengine-web.xml. Is there anything else I am missing?

The single paragraph of documentation on sessions also notes that only objects which implement Serializable can be stored in the session between requests. I have included an example of the code which is not working below.

The obvious solution is to not use redirects, and this might be ok for the example given below but some application data does need to be stored in the session between requests so I need to find a solution to this problem.

EXAMPLE: The class FlashMessage gives feedback to the user from server-side operations.

   if (email.send()) {
        FlashMessage flash = new FlashMessage(FlashMessage.SUCCESS, "Your message has been sent.");
        session.setAttribute(FlashMessage.SESSION_KEY, flash);
        // The flash message will not be available in the session object in the next request
        response.sendRedirect(URL.HOME);
    } else {
        FlashMessage flash = new FlashMessage(FlashMessage.ERROR, FlashMessage.INVALID_FORM_DATA);
        session.setAttribute(FlashMessage.SESSION_KEY, flash);
        // The flash message is displayed without problem
        getServletContext().getRequestDispatcher(Templates.CONTACT_FORM).forward(request,response);
    }

FlashMessage.java

import java.io.Serializable;

public class FlashMessage implements Serializable {
    private static final long serialVersionUID = 8109520737272565760L; // I have tried using different, default and no  serialVersionUID   
    public static final String SESSION_KEY = "flashMessage";            
    public static final String ERROR = "error";
    public static final String SUCCESS = "success";             
    public static final String INVALID_FORM_DATA = "Your request failed to validate.";

    private String message;
    private String type;

    public FlashMessage (String type, String message) {
        this.type = type;
        this.message = message;
    }

    public String display(){
        return "<div id='flash' class='" + type + "'>" + message + "</div>"; 
    }
}
+1  A: 

Perhaps you need to add a default constructor with no arguments.

Ash Kim
I gave it a shot, no glory.
klonq
hmmm... just a guess
Ash Kim
+2  A: 

I turned the log level down to debug and found that AppEngine was throwing Exceptions in the destroy methods of one of its filters. Which is why the objects weren't being saved to session.

I resolved the exceptions and everything works fine.

Hope this helps someone down the line.

klonq
The old app engine up to it's tricks.
Ash Kim