"Session Expired" on Google App Engine

Hi there,

I am currently evaluating Vaadin 7 to see whether it is suitable for the upcoming project in my company.

I’ve made a very simple example, but I am not able to get this running on Google App Engine (GAE). Currently I’ve only tested this on the development server of the GAE.

This is my Root-Class:

package com.gettingmobile.ui.admin;

import com.vaadin.terminal.WrappedRequest;
import com.vaadin.ui.Root;

public class AdminRoot extends Root {
    public AdminRoot() {
        super("Test");
    }

    @Override
    protected void init(WrappedRequest request) {
        setContent(new TestPanel());
    }
}

This is the TestPanel-class

package com.gettingmobile.ui.admin;

import com.vaadin.ui.Button;
import com.vaadin.ui.Panel;

public class TestPanel extends Panel {
    public TestPanel() {
        addComponent(new Button("Click me...", new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                getRoot().showNotification("Test");
            }
        }));
    }
}

My web.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <servlet>
        <servlet-name>Admin App</servlet-name>
        <servlet-class>com.vaadin.terminal.gwt.server.GAEApplicationServlet</servlet-class>
        <init-param>
            <description>Vaadin root</description>
            <param-name>root</param-name>
            <param-value>com.gettingmobile.ui.admin.AdminRoot</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Admin App</servlet-name>
        <url-pattern>/admin/*</url-pattern>
        <url-pattern>/VAADIN/*</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Admin Interface</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
</web-app>

The appengine-web.xml:

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>getting-mobile</application>
    <version>1</version>
    <sessions-enabled>true</sessions-enabled>
</appengine-web-app>

And finally the persistence.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <persistence-unit name="transactions-optional">
        <provider>org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider</provider>
        <properties>
            <property name="datanucleus.NontransactionalRead" value="true"/>
            <property name="datanucleus.NontransactionalWrite" value="true"/>
            <property name="datanucleus.ConnectionURL" value="appengine"/>
        </properties>
    </persistence-unit>

</persistence>

The TestPanel shows up correctly, but as soon as I click the button I get the “session expired” error box shown on the web site.

This is the output I get on the console. The IllegaleStateException is thrown when I click the button:

12.04.2012 09:29:28 com.google.apphosting.utils.jetty.AppEngineAuthentication$AppEngineUserRealm isUserInRole
INFO: Checking if principal test@example.com is in role admin
12.04.2012 09:29:28 com.vaadin.terminal.gwt.server.AbstractApplicationServlet checkProductionMode
WARNUNG: 
=================================================================
Vaadin is running in DEBUG MODE.
Add productionMode=true to web.xml to disable debug features.
To show debug window, add ?debug to your application URL.
=================================================================
12.04.2012 09:29:28 com.google.appengine.api.datastore.dev.LocalDatastoreService init
INFO: Local Datastore initialized: 
	Type: Master/Slave
	Storage: C:\source\playground\MobileServices\out\artifacts\MobileServices_war_exploded\WEB-INF\appengine-generated\local_db.bin
12.04.2012 09:29:28 com.google.appengine.api.datastore.dev.LocalDatastoreService load
INFO: The backing store, C:\source\playground\MobileServices\out\artifacts\MobileServices_war_exploded\WEB-INF\appengine-generated\local_db.bin, does not exist. It will be created.
12.04.2012 09:29:28 com.google.apphosting.utils.jetty.AppEngineAuthentication$AppEngineUserRealm isUserInRole
INFO: Checking if principal test@example.com is in role admin
12.04.2012 09:29:30 com.google.apphosting.utils.jetty.AppEngineAuthentication$AppEngineUserRealm isUserInRole
INFO: Checking if principal test@example.com is in role admin
12.04.2012 09:29:30 com.vaadin.terminal.gwt.server.GAEApplicationServlet service
WARNUNG: An exception occurred while servicing request.
java.lang.IllegalStateException
	at org.mortbay.jetty.servlet.AbstractSessionManager$Session.getMaxInactiveInterval(AbstractSessionManager.java:849)
	at com.vaadin.terminal.gwt.server.GAEApplicationServlet.service(GAEApplicationServlet.java:254)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
	at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:35)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:60)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:78)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:369)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
12.04.2012 09:29:58 com.google.appengine.api.datastore.dev.LocalDatastoreService$PersistDatastore persist
INFO: Time to persist datastore: 33 ms

If I instead do not derive my own Panel-class, but inline it directly in the AdminRoot like shown in the following code, then it works:

    @Override
    protected void init(WrappedRequest request) {
        final Panel panel = new Panel();
        panel.addComponent(new Button("Click me...", new Button.ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                getRoot().showNotification("Test");
            }
        }));
        setContent(panel);
    }

In your root’s init method add

getApplication().setRootPreserved(true);

Hi Sven,

Are you still facing this issue?


java.lang.IllegalStateException
    at org.mortbay.jetty.servlet.AbstractSessionManager$Session.getMaxInactiveInterval(AbstractSessionManager.java:849)

I too find this error message sometimes now in local app console, however, this doesn’t seem to appear in live GAE (i.e after deployment).