Contextual injection of core domain concepts with Seam

Update: Pete Muir recently posted an alternative to the example described here for the UserProfile object. It avoids potential LazyInitializationException if you access a property which was not initialized inside the loading conversation since the UserProfile is SESSION scoped. I prefer Pete’s approach to the implementation but the concept is the same 😉
______________________________________________________________

One thing I have really come to appreciate in seam is the ask and ye shall receive approach of injection of not only components but also core domain objects (or concepts depending on how you look at it). One issue I’ve always struggled with is the requirement to constantly go and get some domain object that is used very often. This really reminds me of the EJB2 style lookups which was really why we starting using DI frameworks, right? Whether you look up the domain object through a DAO, through the session, or through some holder object, you still have to go and get what you need.

For example, let’s say we have a UserProfile object that is needed by most of our pages and many of the components in our application to retrieve user information. It may not always be needed (we have an Identity of course thanks to Seam which provides our authentication and authorization), but it is needed if we require personal information about our user.

In the general world of Java you could implement this in several ways but lets say we do so through something like the following:

public class UserInformationBean implements UserInformation
  ...
  private UserProfile userProfile;        

  // injected by your favorite DI framework
  // (Seam, EJB3, Spring, even PicoContainer)
  private UserProfileDAO userProfileDAO;
  ...
  public boolean isUserLocal()
  {
    UserProfile userProfile = this.getUserProfile();  

    if("Texas".equals(userProfile.getState())
        && "Dallas".equals(userProfile.getCity()))
    {
      return true;
    }        

    log.info("ya'll ain't from around here are ya");

    return false;
  }
  ...
  public UserProfile getUserProfile()
  {
    if(userProfile == null)
    {
      this.userProfile =  userProfileDAO.getUserProfile(
        SomeContext.getUserPrincipal().getName());
    }        

    return this.userProfile;
  }
  ...

Here is the associated dependency diagram for our UserInformationBean component:

This is all well and good but I would prefer if the call to retrieve the UserProfile was centralized since I use it often. This is quite easy with Seam:

@Name("userProfileManager")
public class UserProfileManager {
  ...
  @In private UserProfileDAO userProfileDAO;
  ...
  @Factory(value="userProfile", scope=ScopeType.SESSION,
                 autoCreate=true)
  public UserProfile initCurrentUserProfile()
  {
    return userProfileDAO.getUserProfile(
               Identity.instance().getUsername());
  }
  ...

Note that I scope my UserProfile to the session which makes sense since the user is not likely changing profiles (or we may be in for some legal issues) and we are using it throughout the application. Note that conversation scope should be considered if the object is only needed in a section of the application to ensure that our state is cleaned up appropriately. The use of other contexts will be discussed further shortly. So now my component looks like:

@Name("userInformation")
public class UserInformationBean implements UserInformation
  ...
  @In UserProfile userProfile;
  ...
  public boolean isUserLocal()
  {
    if("Texas".equals(userProfile.getState())
        && "Dallas".equals(userProfile.getCity()))
    {
      return true;
    }

    log.info("ya'll ain't from around here are ya");

    return false;
  }
  ...

Below is the dependency diagram for our UserInformationBean after the change. Note that our UserInformationBean knows nothing about the UserProfileDAO (nor does it care):

So you may ask what does this buy me? I still have to call the DAO to get what I need. Sure, you may have to call your DAO (or the EntityManager if your using EJB3), but the dependency on the DAO is in one place, not scattered. Your component is now only dependent on what it needs to get the job done and we’ve removed unnecessary layering thereby reducing coupling.

In addition, the factory method only executes once during the course of a user session as I’ve scoped my UserProfile to the session. Thus, the UserProfile is instantiated lazily (since the @Factory method only executes on demand) and if it is used elsewhere it is simply provided back from the context rather than invoking the DAO again.

I also find this approach much easier to test. Rather than having to provide a mock DAO (or even worse a mock EntityManager) to my component, I simply set the UserProfile to whatever I need it to be to perform my unit test:

...
public void testIsUserLocal()
{
  UserProfile = new UserProfile("Jacob Orshalick", "Dallas", "Texas");
  UserInformationBean bean = new UserInformationBean();        

  bean.setUserProfile(userProfile);        

  assertTrue("Howdy!  Ya'll oughta be returnin' true.",
    bean.isUserLocal());
}
...

Additional Considerations

One drawback to this approach is determining where these domain objects are coming from. It may not be immediately obvious as to how these objects are just appearing in the context for developers. One approach to help with this is using symbolic constants. Using our example above we could create a constant for the UserProfile:

...
public final static String USER_PROFILE = "userProfile";
...

We can use this in both the factory and the injection:

...
@Factory(value=DomainConstant.USER_PROFILE, scope=ScopeType.SESSION,
               autoCreate=true)
...
@In(value=DomainConstant.USER_PROFILE)
UserProfile userProfile;
...

In this way a user can easily seek out where USER_PROFILE is referenced rather than having to do a text search (which could easily result in a vast number of results especially if used in EL expressions and comments).

Another consideration here is how your domain object will be used. This is necessary to determine which context to outject to. Is my UserProfile being used heavily in all of the application or is it only a section of the application? Conversation context would be a better candidate if the UserProfile is heavily required in a certain section of the application. Also, what are the memory penalties involved? Would it be better to simply request when needed to avoid the additional memory allocation? This may be the case if the object is used infrequently. It may be best to inject a local instance only that is only used for the invocation. Developers should always carefully consider the context.

Bijection and Disinjection

One way to explicitly control the scope of the creation of the UserProfile would be to leave off the ScopeType in your @Factory definition. Because a POJO is by default EVENT scoped, the UserProfile would only be available to your component and you choose whether to outject it to a broader context. This can simply be accomplished through use of the @Out annotation.

If you choose to leave off the ScopeType and inject a local instance in your component, the @Factory method would be invoked once for each request that your component is invoked. Why is that you ask? Essentially, Seam disinjects any attributes in your component annotated with @In after the invocation. Disinject is really just a fancy way of saying set to null.

This is an important concept as you may expect your attribute to remain set in between requests if I scoped my component to the Conversation or the Session. This behavior makes sense though as Seam maintains contextual state. The current context state is always injected into your component for each invocation. Therefore, it makes no sense to maintain the attribute instance as it will be overwritten prior to the next invocation.

This type of domain concept injection is very useful as it helps to reduce coupling and the heavy layering constantly introduced into systems. There are many situations where this type of behavior is quite handy but it is only achievable due to the contextual injection that Seam provides.

Session expired messages using Seam security

Differentiating between an initial login, a session expired, and a logout when displaying messages to the user on the login screen seems like a simple task. The implementation is unfortunately not quite as simple as it sounds and requires a little legwork. The following tutorial will guide you through the requirements.

The first component is a PhaseListener that allows you to determine whether the user’s session expired or whether this is the first time the user accessed the application. You have to make some assumptions here, but you can basically notify the user when the server session has ended by adding the following to a PhaseListener:

...

@Observer("org.jboss.seam.beforePhase")
public void beforePhase(PhaseEvent event)
{
  if(event.getPhaseId() == PhaseId.RESTORE_VIEW)
  {
    HttpServletRequest request =
      (HttpServletRequest) FacesContext.getCurrentInstance()
        .getExternalContext().getRequest();

    if(request.getRequestedSessionId() != null
           && request.getSession().isNew())
       Events.instance().raiseEvent("security.sessionExpired");

       ...

Based on general cookie settings this will raise the event when the user still has the browser window open, the http session expired, and the user tries to access the application. If the user closes and reopens the browser to start the application, the event will not be raised. This of course makes the assumption that cookies expire when the browser session is ended (which is generally the case).

This works well, but unfortunately the FacesMessages component is not available until after the RENDER_RESPONSE phase has executed. This is because the FacesMessages component is conversation scoped and the conversation is not started until after the RENDER_RESPONSE phase. Thus, you have to have a component available to store your message until the FacesMessages component becomes available. This can be accomplished by using an appropriately scoped component. For example:

@Name("customAuthenticator")
@AutoCreate
@Scope(SESSION)
public class CustomAuthenticator implements Authenticator {
    @Logger
    private Log log;
    ...
    private List<string> messages;
    ...
    @Observer("security.sessionExpired")
    public void sessionExpired(String message)
    {
        log.info("Adding session expired message...");

        this.messages.add("User session expired.");
    }

    public void flushMessages()
    {
        for(String message : this.messages)
            FacesMessages.instance().add(message);

        this.messages.clear();
    }
}

The flushMessages method should be invoked either by an action on your pages.xml or by flushing after the INVOKE_APPLICATION phase (this is up to your preference). Simply ensure that the flushing occurs only once the conversation has been initialized so that FacesMessages is available in the context.

This takes care of differentiating between a session timeout and a new session. So what about the logout? If you flush the security messages on every request, the user will end up seeing a message saying that the “User session ended” on logout.

To resolve this we can place a page in between and perform a meta redirect. First define a Seam page that does not require a login. Then in this page, add the following meta tags:

<meta http-equiv="Refresh" content="3; URL=/myApp/myPage.seam" />

This page can display a simple message to the user along the lines of: “You have successfully logged out.” The user will then be redirected to myPage after 3 seconds. As long as the messages are flushed on each request, the “User session ended” message will be long gone once the meta redirect executes.

Next add an entry in your pages.xml to redirect to this page when a logout occurs:

<page view-id="*">
  <navigation from-action="#{identity.logout}">
    <redirect view-id="/logoutConfirmation.xhtml" />
  </navigation>
</page>

A feature request has been placed to include the security.sessionExpired event as well as a security.newSession event. If you are interested in Seam providing this behavior out-of-the-box, please vote!

Update: Are you looking for an advanced polling solution for session expiration? Christian Bauer blogged about an approach to polling for session expiration here.

Solution using Seam to pagination issue with JSF on DataModel updates

In an implementation using the JBoss RichFaces rich:dataScroller component, I noticed the first attribute of a UIData component is maintained even if the DataModel it is displaying has changed. It turns out, this is an issue with JSF. The UIData component does not track the DataModel it represents. Thus, when the DataModel is updated it has no effect on the first attribute of the UIData component. In defense of JSF, it would be difficult to know when a DataModel update should trigger an update of the UIData as this would require making some assumptions about the model.

As you can imagine, this can lead to consistency issues with data versus the state of the UI when pagination is used. For example, if I have a DataModel that wraps a List of 100 elements that are the results of a search. In the display, I can show 10 elements per page and allow the user to paginate freely with the rich:dataScroller component. If the user paginates to the fifth listing, the first attribute of the UIData component now points to 50. If the user then narrows the search (by changing some search criteria and re-submitting) the result set is reduced to 10. Now we have an issue. The user sees no results because the UIData is looking for index 50 to start the List. The first attribute does not get updated to reflect the change in the model.

So how can we resolve this? A simple Seam interceptor would do the trick (if you are already using stereotypes this will be a snap). Assuming you have not yet created a stereotype for your Action classes, the following steps can be taken,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Interceptors(ActionInterceptor.class)
@Inherited
public @interface Action {}

This will ensure that any @Action class will be intercepted by the ActionInterceptor. Now create a method-level annotation similar to the following:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Search {
  String dataTableId();
}

The dataTableId is the component ID of the DataTable in your page. Note: This will require that you specify unique IDs for your components which is good practice in JSF anyway. Next, you must provide the interceptor which does the work of reseting the first attribute for the component. When an @Search action is executed that resets the DataModel, we want to reset the UIData:

@Interceptor(stateless=true)
public class ActionInterceptor implements Serializable
{
  ...
  @AroundInvoke
  public Object aroundInvoke(InvocationContext invocation)
      throws Exception
  {
    Method method = invocation.getMethod(); 

    if(method.isAnnotationPresent(Search.class))
    {
      UIComponent component = FacesContext
        .getCurrentInstance().getViewRoot()
        .findComponent(searchAnnotation.dataTableId()); 

      if(component != null && component instanceof UIData)
      {
        UIData dataTable = (UIData) component; 

        dataTable.setFirst(0);
      }
    } 

    result = invocation.proceed();
  }
...

You would probably want to add your own exception handling to this as well. Finally, we can use it in our application:

@Name("myAction")
@Stateful
@Action
public class MyActionBean implements MyAction {
  ...
  @DataModel
  List<myentity> searchResults;
  ...
  @Search(dataTableId="myForm:searchResults")
  public void search() throws Exception
  {
    searchResults = entityManager.createQuery(...)
       .getResultList();
  }
  ...

As I mentioned before, if stereotypes are already being used, this becomes a snap. Simply add the @Search annotation and add the code to handle the dataTable reset in your existing ActionInterceptor.

Alleviating client-side back-button issues with Ajax4JSF and RichFaces

Recently an article I wrote was published on the Seam conversation model and how issues with the back-button can be eliminated through a continuation approach. This aids developers in resolving back-button issues with respect to server-side state, but what about the client-side. Ajax development is a breeze with Seam especially when used in conjunction with Ajax4JSF and RichFaces but the use of Ajax can result in issues with caching of client-side state.

Caching is a common issue with Ajax implementations though many of the concerns of caching are alleviated by using the Ajax4JSF/RichFaces libraries (which I highly recommend). The specific problem I would like to address applies to use of Internet Explorer with Ajax (Firefox does not suffer from the problem). Internet Explorer caches pages when the entire page is refreshed. Ajax implementations allow the page to be altered without a refresh, only re-rendering the applicable section of the page. Thus, if a user submits a page or navigates elsewhere, using the back- or forward-button to return to the page will not display any portions of the page that had been updated by Ajax calls. Instead the page will be shown based on what was cached when the page was originally rendered. Firefox, on the other hand, maintains an up-to-date cache that displays the page as it was rendered after any AJAX updates in response to interaction with the user.

If you don’t believe me, try it yourself! Go to maps.google.com and view a map of your favorite location using Internet Explorer. Now type a new URL into your browser and navigate to it. Press the back button and *poof* you’re back at square one. The map of your favorite location is gone. Now perform the same steps using Firefox. Wow, Firefox still shows the map and you can still see your favorite location!

This is a rather annoying issue and of course could lead to issues with our conversation state (not to mention confusion of the users). Not to fear, the issue can be resolved through a fairly simple solution. Internet Explorer invokes the onload function every time a page is displayed (whether through the initial rendering, the back-, or the forward- button). The following code will resolve your issue using Ajax4JSF which ships with JBoss RichFaces:

<body bgcolor="#FFFFFF" text="#000000"
      onload="reloadAjaxPanels()">
  <h:form id="myAjaxForm">
    <a:jsFunction name="reloadAjaxPanels"
                  reRender="panelToReload" />
      ...
    <a:outputPanel id="panelToReload">
    ...
    </a:outputPanel>
  </h:form>

Now each time the user backs up to the page the Ajax panels will be updated according to the state of the current conversation. The downsides to the solution are that the user will notice a flash each time he or she backs up to the page (when the Ajax components reload) and it causes (what I would consider unnecessary) traffic between the client and the server. If this is acceptable, this solution will help you to use Ajax and Seam together to allow applications to behave according to a user’s expectations rather than the developer’s.