Physical Request-Scoped Attributes for JSF in Portlets

One of the more frustrating parts of portal development is the fact that the Portal Specification does not follow good “design by contract” principals. One aspect of this deficiency is how the behavior of request-scoped attributes is defined in the portlet specification.

In the servlet world, there is one Request object for each physical request from the the browser. This is called a single-phased request. Because of their complexity and the need to enable applications to perform better, the Portlet 1.0 specification introduced a multi-phased request in which certain types of requests are run in response to certain types of requests. This means that rendering logic can be light and fast in its implementation while data-fetching logic and processing could be done only when a portlet is the target of its own request.

Although this approach has merit, the Portal Specification does not clearly outline the lifespan of a request-scoped attribute. Many portal vendors (quite incorrectly in my opinion) say that items added to the request during the processAction will NOT be available during the render. While other vendors, including the R.I. do preserve these attributes between an action and its render request. This means that different containers behave differently depending on their implementation, which is something that directly violates “Design by Contract” principals.

JSR-301 Portlet Bridge’s Take

The JSR-301 Specification tries to address this inconsistency for JSF applications by stating that Request Attributes which are added during a JSF Action phase of the lifecycle, should be available during the following render and all subsequent renders. This allows a situation where a JSF portlet which needs to be rendered as a result of another portlet’s action, can simply continue by running the render portions of the lifecycle. This behavior happens regardless of behavior and although there may be some challanges in dealing with this nuance, it will remain consistent across portal boundries.

For those attributes that should NOT be around for subsequent renders, like per-request state information, JSR-301 added a special configuration as well as an “@ExcludeFromManagedRequestScope” attribute which allows an attribute to remove itself from this feature. For example, let’s say a renderkit stores an attribute on the request which holds a flag telling the renderkit to render in XML (for an Ajax request) rather then html. If this bean persisted to multiple requests, you might find that your renderkit would render ajax content directly into your portlet’s window on the portal page. This is NOT the desired result.

Where JSR-301 falls short, however, is that it does not enforce any sort of consistency when a bean is excluded from the managed request scope, instead it defers to the logic defined by the portal container. As such, attributes which are excluded from the managed request scope suffer from the same implementation-specific problems that the Portlet 1.0 containers suffer from.

The good stuff

There are several ways to handle this situation. The first is to make sure that beans are able to be re-created on an as-needed basis, even from a portlet render request. This is a challange in a portlet environment because parameters which are passed into the action are not available during the subsequent render request unless they are explicitly added. Furthermore, if the parameters are added, they will be added to every Render request until either a render request is called specifically or until antoher action is called on the portlet. In either case, this suffers the same pitfalls as the bridge’s managed request scope, so if your initialization state is dependent on incoming parameters for your initialization, it will be very difficult for you to manage this manually.

Another approach, and the one which I will concentrate on here, is to develop your own mechanism for preserving request attributes from action to render. Before I get started, I also want to make some comments about the code. This code it an example which I’m using to illustrate an idea. As such, I’m not worrying about thread safety and robustness so much as I’m trying to illustrate an idea. If you want a pre-canned solution, I will likely be adding one to the configurator mechanism that I currently have under development, so keep watching this blog for further details.

The code below outlines the usage of a custom FacesContext Decorator.

  public class FacesContextImpl implements FacesContext
  {
    private FacesContext _orig;
    public static final String STATE_NAME = "scottobryan.STATE";
    public FacesContextImpl(FacesContext context)
    {
      _orig = context;
      ExternalContext ec = getExternalContext();
      Map<String, Object> saved = null;
      if(ec.getRequest() instanceof RenderRequest)
      {
        /*
         *First we look to see if we have a stored state
         *For this example I'm using the session but you can
         *use other scopes
         */
        saved = (Map<String, Object>)ec.getSessionMap()
                                         .remove(STATE_NAME);
      }

      if(saved == null)
      {
        saved = new HashMap<String, Object>();
      }

      ec.getRequestMap().put(STATE_NAME, saved);

      //TODO your other logic here
    }

    //TODO all other methods should delegate except release
    @Override
    public void release()
    {
      ExternalContext ec = getExternalContext();
      if (ActionRequest) instanceof ec.getRequest())
      {
        Map<String, Object> state =
         (Map<String, Object>)ec.getRequestMap()
                                  .remove(STATE_NAME);
        ec.getSessionMap().put(STATE_NAME, state);
      }

      _orig.release();
    }
  }

Lines 17 and 18 are responsible for trying to get the state off the session if it exists. If it does not then a new state map is created regardless of environment.

Lines 33 to 46 will save the map to the session when the FacesContext is release by the bridge. It will only do this on an action request since that’s the only usecase we care about. For cleanliness I go ahead and remove it from the request, but an uglier (albeit faster) technique might be to try to leave it on the request so that during the next render you can figure out whether you are in a container which preserves request attributes and are therefore able to disable this caching altogether.

The code will make sure that there will be a map stored on the request attributes by the name of STATE_NAME and that any attributes which are appended to it will be available throughout the lifetime of the physical request. If you have a container that is not tolerant of non-serializable data on the session (by spec it should be, just not for failover), you can either make all your stuff serializable or you can play around with appending it to the Application scope.

Also, it might be good to be able to encode some sort of id that can be used to tell whether the state belongs to a certain render request or not in case something happens and the render does not follow the action for which is was intended. This could happen as a result of a network hickup on a remote (WSRP) portal, but I’m hoping that in such circumstances portals are able to recover better.

Enjoy!

~ by scottobryan on July 3, 2008.

Leave a Reply