Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Minor layout tweaks
Wiki Markup
{float:right|}
{panel:background=#eee|title=Contents}
{contentbylabeltoc:titleminLevel=Related Articles2|showLabels=false|showSpace=false|space=@self|labels=persistencemaxLevel=4}
{panel}
{float}

Session Storage

...

Most web applications will need to have some data that is shared across multiple pages. Perhaps you are creating a multi-page wizard, or you have an object that tracks the user's identify once logged in, or maybe you need to manage a shopping cart.

...

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

Wiki Markup
{float:right|background=#eee}
{contentbylabel:title=Related Articles|showLabels=false|showSpace=false|space=@self|labels=persistence}
{float}

Example:

Code Block
java
java

public class MyPage
{
  @SessionState
  private ShoppingCart shoppingCart;
  
  . . .
}

...

Code Block
titleExample of Data Collision -- Don't Do This!

  @SessionState
  private String userName;     // Unsafe -- String is not a custom type

  ... then, later in this class or any other:

  @sessionState
  private String userCity;     // This overwrites value in userName, because it's also a String!

...

Instead, create a second field with a matching name but with "Exists" appended:

Code Block
java
java

  private boolean shoppingCartExists;

...

Alternately, you may allow for the state being null:

Code Block
java
java

  @SessionState(create=false)
  private ShoppingCart shoppingCart;

...

A Session State Object is configured using contributions to the ApplicationStateManager service. From your application's module:

Code Block
java
java

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

...

Session Attributes

Since
since5.2
 

As an alternative to SSOs, Tapestry provides a Session Attribute mechanism, which lets you store data in the session by name (rather than type). It is particularly useful when integrating Tapestry with legacy applications that directly manipulate the HttpSession.

Code Block
titleThe Old Way

public class Page {
    @Inject
    private Request request;
    
    public User getUser() {
        return (User) request.getSession(true).getAttribute("loggedInUserName");
    }
}

...

Code Block
titleThe New Way

public class Page {
    @SessionAttribute
    private User loggedInUserName;
}

You can also provide a name using the annotation's value parameter:

Code Block

public class Page {
    @SessionAttribute("loggedInUserName")
    private User userName;
}

...

Code Block
titleThe Safer Way

public static final String USER_NAME_SESSION_ATTRIBUTE = "com.example.shoppingapp.username";

...

public class Page {
    @SessionAttribute(USER_NAME_SESSION_ATTRIBUTE)
    private User userName;
}

Include Page
Clustering Issues
Clustering Issues

Session Locking

Starting with version 5.4, by default Tapestry will apply locking semantics around access to the HttpSession. Reading attribute names occurs with a shared read lock, and getting or setting an attribute upgrades the lock to an exclusive write lock. This can tend to serialize threads when a number of simultaneous (Ajax) requests from the client arrive. However, many implementations of HttpSession are not thread safe, and often mutable objects
are stored in the session and shared between threads.

...

Code Block
titleAppModule.java (partial)

  public static void contributeApplicationDefaults(MappedConfiguration<String,String> configuration)
  {
    configuration.add(SymbolConstants.SESSION_LOCKING_ENABLED, true);
    ...
  }