Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Unfortunately GWT has not made it easy to use continuations within their RPC mechanism. Firstly they catch Throwable, so the Jetty RetryException is caught. Secondly they have made most of the methods on the GWT servlet final, so you cannot fix this by extension.

GWT 1.5.x and below

Luckily GWT is open sourced under the apache 2.0 license, so it was possible to do a cut/paste/edit job to fix this. The OpenRemoteServiceServlet recently added to Jetty is a version of GWTs RemoteServiceServlet without the final methods and a protected method for extending exception handling.

...

Code Block
java
java
protected String readPayloadAsUtf8(HttpServletRequest request)
      throws IOException, ServletException
{
    String payload=(String)request.getAttribute( PAYLOAD );
    if ( payload==null )
    {
        payload=super.readPayloadAsUtf8( request );
        request.setAttribute( PAYLOAD,payload );
    }
    return payload;
}

GWT 1.6.x+

The OpenRemoteServiceServletis no longer needed.  The RemoteServiceServlet has been updated and the limitations mentioned above are no more.  You can either patch a copy of AsyncRemoteServiceServletin your project, until a new jetty-gwt.jar release, or override the readContent(HttpServletRequest request) and doUnexpectedFailure(Throwable caught) in your subclass.  Here is the overide for that replaced readPayloadAsUtf8 as mentioned above.

Code Block
java
java

protected String readContent(HttpServletRequest request)
      throws IOException, ServletException
{
    String payload=(String)request.getAttribute( PAYLOAD );
    if ( payload==null )
    {
        payload=super.readContent( request );
        request.setAttribute( PAYLOAD,payload );
    }
    return payload;
}

The exception handling is also extended to allow the continuation RetryException to propagate to the container. This has been done without any hard dependencies on Jetty code. With these extensions, the AsyncRemoteServiceServlet allows any GWT RCP method to use continuations to suspend/resume processing. All you need to do is to have your servlet implementation extend the org.mortbay.gwt.AsyncRemoteServiceServlet:

...

Code Block
java
java
class Table
{
    Set waiters = new HashSet();

    public Events getEvents( Context c )
    {

        Player p = getPlayer( c );
        // the player has no events.
        if( p.events.size() == 0 )
        {
            synchronized( this )
            {
                // suspend the continuation waiting for events
                Continuation continuation =
                  ContinuationSupport.getContinuation
                  ( c.getRequest(),this );
                waiters.add( continuation );
                continuation.suspend( 30000 );
            }
        }

        return p.events;
    }

    protected void addEvent( Event e )
    {
        // give the event to all players
        Iterator it = players.values().iterator();
        while( it.hasNext() )
        {
            Player p = (Player)it.next();
            player.events.add( event );
        }

        // resume continuations waiting for events
        synchronized( this )
        {
            Iterator iter = waiters.interator();
            while ( iter.hasNext() )
                ( (Continuation)iter.next() ).resume();
            waiters.clear();
        }
    }
}

GWT 1.5.x and below

You will need to build and then include the jetty-gwt-<version>.jar in your webapp. The source is included with every download of jetty. To build:

...

Code Block
// Accessor needs to be protected
  private final ThreadLocal<HttpServletRequest> perThreadRequest = new ThreadLocal<HttpServletRequest>();

  private final ThreadLocal<HttpServletResponse> perThreadResponse = new ThreadLocal<HttpServletResponse>();

GWT 1.6.x+

Just extend RemoteServiceServlet and override readContent(HttpServletRequest request), shown above, and doUnexpectedFailure(Throwable caught).

Code Block
java
java

private static final String JETTY_RETRY_REQUEST_EXCEPTION = "org.mortbay.jetty.RetryRequest";

/**
 * Overridden to really throw Jetty RetryRequest Exception (as opposed to sending failure to client).
 *
 * @param caught the exception
 */
protected void doUnexpectedFailure(Throwable caught)
{
    throwIfRetryRequest(caught);
    super.doUnexpectedFailure(caught);
}

/**
 * Throws the Jetty RetryRequest if found.
 *
 * @param caught the exception
 */
protected void throwIfRetryRequest(Throwable caught)
{
    if (caught instanceof UnexpectedException) {
        caught = caught.getCause();
    }

    if (JETTY_RETRY_REQUEST_EXCEPTION.equals(caught.getClass().getName()))
    {
        throw (RuntimeException)caught;
    }
}
Contact the core Jetty developers at www.webtide.com
private support for your internal/customer projects ... custom extensions and distributions ... versioned snapshots for indefinite support ... scalability guidance for your apps and Ajax/Comet projects ... development services from 1 day to full product delivery