7.9 Referencing the Request and Session

Flash Remoting services do not have access to the HttpServletRequest request object created by the Flash client Remoting service call. Nor do they have access to the HttpSession user session object associated with that request. Many developers using Flash Remoting find that they need access to both. The request object has useful information about the user making the request. Developers frequently use the user session object to store information specific to that user while the user is using the application.

The most common reason for accessing the request and user session objects is to integrate with a user-authentication system, either standard Container-Managed Security supported by Servlet 2.3 J2EE application servers or a homegrown system that stores information in the user session object.

If we can gain access to the HttpServletRequest object, we can also access the user session via HttpServletRequest.getSession( ), so let's focus on the first goal. One solution is to write a servlet filter, available in Servlet 2.3 application servers, that associates the request with the current thread before the request is handled by the Remoting gateway. Servlet filters can act on the request and response objects before and after they are handled by a servlet.

By associating the request with the current thread before the request is handled by the Remoting gateway, any code running in the same thread can retrieve a reference to the request. Two classes provide this implementation: RequestContextFilter and RequestContext. Let's look at RequestContextFilter first:

public class RequestContextFilter
  implements javax.servlet.Filter
{
  public void init(FilterConfig config) throws ServletException { }
  public void destroy( ) { }

  public void doFilter(ServletRequest request,
                       ServletResponse response,
                       FilterChain chain)
    throws IOException, ServletException
  {
    RequestContext.setRequest(request);
    chain.doFilter(request, response);
  }
}

RequestContextFilter sets the request in the RequestContext and calls the next filter in the filter chain. A filter is defined and mapped to a URL in the application's web.xml file similarly to a servlet. You should map RequestContextFilter to the Flash Remoting gateway URL, as shown here, to set the request in RequestContext for every Remoting service call:

<filter>
  <filter-name>RequestContextFilter</filter-name>
  <filter-class>com.oreilly.frdg.java.RequestContextFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>RequestContextFilter</filter-name>
  <url-pattern>/gateway</url-pattern>
</filter-mapping>

RequestContext, shown here, provides methods for setting and retrieving the current request and for getting the HttpSession directly from the current request:

public class RequestContext {
  // ThreadLocal( ) is associated with the current thread.
  private static ThreadLocal localRequest = new ThreadLocal( );

  // Get the request from the current thread.
  public static ServletRequest getRequest ( ) {
    return (ServletRequest) localRequest.get( );
  }

  // Set the request in the current thread.
  public static void setRequest (ServletRequest request) {
    localRequest.set(request);
  }

  // If it is an HttpServletRequest, get the request from the current thread.
  public static HttpServletRequest getHttpRequest ( ) {
    if (getRequest( ) instanceof HttpServletRequest) {
      return (HttpServletRequest) getRequest( );
    }
    return null;
  }

  // Get the session from the HttpRequest in the current thread.
  public static HttpSession getSession ( ) {
    if (getHttpRequest( ) == null) return null;
    return getHttpRequest( ).getSession(true);
  }
}

RequestContext relies on the magical behavior of the java.lang.ThreadLocal class, which gives developers the ability to associate different instances of an object with each thread in an application. For more details on using ThreadLocal, see one of the Java books cited in Appendix B.

Use RequestContext.getHttpRequest( ) to get a reference to the current request from a Remoting service method when using the RequestContextFilter and RequestContext implementation we just discussed. The following example is a Remoting service, ContainerLoginService, with a method, isUserLoggedIn( ), that returns true if the current user has logged in using Container-Managed Security. HttpServletRequest.getUserPrincipal( ) returns a java.security.Principal object if the user has logged in through Container-Managed Security:

public class ContainerLoginService {
  public boolean isUserLoggedIn ( ) {
    HttpServletRequest request = RequestContext.getHttpRequest( );
    return request.getUserPrincipal( ) != null;
  }
}

We add another method, getLoggedInUser( ), to ContainerLoginService in the following example. The getLoggedInUser( ) service method uses the Directory service to return the logged-in user to a Flash client. Principal.getName( ) returns the username of the logged-in user, which we use to look up the user in the Directory:

public class ContainerLoginService {
  public ASObject getLoggedInUser ( ) {
    if (!isUserLoggedIn( )) return null;

    Principal p    = RequestContext.getHttpRequest( ).getUserPrincipal( );
    User      user = Directory.getUser(p.getName( ));

    return (ASObject) new ASTranslator( ).toActionScript(user);  }
}


    Part III: Advanced Flash Remoting