You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Persistent State

Often, you will have a situation where you have a bit of data that is needed across multiple pages. Perhaps you are creating a multi-page wizard, or perhaps you have an object that tracks the user's identify once logged in.

Ordinary persistent page data is not appropriate, since persistent fields apply to a specific page and aren't shared across pages.

Instead, you want to use a Session State Object (an SSO).

With an SSO, the value is automatically stored outside the page; with the default storage strategy, it is stored in the session. Such a value is global to all pages for the same user, but is stored seperately for different users.

A field holding an SSO is marked with the SessionState annotation.

Example:

public class MyPage
{
  @SessionState
  private MyState myState;
  
  . . .
}

Any other component or page that declares a field of the same type, regardless of name, and marks it with the SessionState annotation will share the same value. It's that simple.

For Tapestry 4 Users: a big change here is that you don't need to provide any configuration for the SSO before using it, nor do you provide a logical name. Tapestry 5 uses the class name to identify the SSO, so there's no need for a logical name.

The first time you access an SSO, it is created automatically. Typically, the SSO will have a public no-args constructor ... but you may inject dependencies into the SSO via its constructor, as you can with a Tapestry IoC service implementation.

Assigning a value to an SSO field will store that value. Assigning null to an SSO field will remove the SSO (reading the field subsequently will force a new SSO instance to be created).

Check for Creation

Scalable web applications do not create the server-side session needlessly. If you can avoid creating the session, especially on first access to your web application, you will be able to handle an order of magnitude more users. So, if you can avoid creating the SSO, you should do so.

But how to avoid creating it? Simply checking ("myState != null") will force the creation of the SSO and the session to store it in.

Instead, create a second field:

  private boolean myStateExists;

This companion field is used to see if the SSO already exists. It is not annotated; it is located by name ("Exists" is appended to the name of the field storing the SSO). It must be type boolean and must be a private instance variable.

Alternately, you may allow for the state being null:

  @SessionState(create=false)
  private MyState myState;

In this case, the myState field will be null if the MyState SSO does not exist, but will be non-null if it has been created (either by assigning a value to the field, or by a different SSO field where create is true).

Persistence Strategies

Each SSO is managed according to a persistence strategy. The default persistence strategy, "session", stores the SSOs inside the session. The session is created as needed.

Clustering Issues

The clustering strategy for Application State Objects in release 5.0 now applies to all session-persisted objects. See the persistent page data notes for more details.

Configuring SSOs

Generally, you will configure an SSO if you need to change it from the default persistence strategy. Right now there's only one built in strategy, but more will be coming in the future.

Alternately, you will configure an SSO so that you can control how it is instantiated. You may need to inject some values into the SSO when it is first created, or otherwise initialize it. In this second case, you may provide an ApplicationStateCreator object, which will be called upon to create the SSO as necessary. This is also the technique to use when you want your SSO to be represented by an interface rather than a class: you need to provide a creator that knows about the class that implements the interface.

Contributions to the ApplicationStateManager service are used to configure an SSO. From your application's module:

  public void contributeApplicationStateManager(MappedConfiguration<Class, ApplicationStateContribution> configuration)
  {
    ApplicationStateCreator<MyState> creator = new ApplicationStateCreator<MyState>()
    {
      public MyState create()
      {
        return new MyState(new Date());
      }
    };
  
    configuration.add(MyState.class, new ApplicationStateContribution("session", creator));
  }

Here, we have an SSO type of MyState, and we're providing a creator for it. We've dolled the creator up with some generic types, but that isn't essential.

Our creator creates a new MyState instance using an alternate constructor that takes the current date and time. Again, just an example.

Finally, we create an ApplicationStateContribution identifying the strategy name and the creator, and give that to the configuration.

Note: You might be confused by the name "_Application_StateManager" and "_Application_StateCreator"; these reflect a difference in naming between 5.0 and 5.1; SSOs were originally called "Application State Objects", but that naming implied they were stored in the ServletContext, as application global to all users. The new SessionState annotation was introduced, but the existing services need to keep thier names as-is.

  • No labels