As I mentioned in a previous blog, I’ve been playing around a little with the Click framework in the hopes of having stumbled on a front end framework that is suitable for people like me (who really don’t like the front end). But while I think that Click is quite clever in a number of its ideas, it is not quite what I was hoping.

So being somewhat disappointed with the results of my experiment, I got to thinking about why I don’t like the front end and what should change. And I’ve come to the conclusion that at the very least a large part of what I don’t like is session management as it has been defined by Sun on the server side.

In this blog entry I will explain where I think JEE session management causes you to run off the rails and what I think might be an alternative.


The ideal architecture

In order to explain my likes and dislikes, let me start by describing what I consider to be the “ideal architecture” of the modern business application: the architecture that allows maximum reuse of the business core of the application and maximum flexibility with respect to front end exposure and backend service use.

Somewhat unsurprisingly, this architecture is very similar to the standard three-tier application architecture. As a diagram it looks like this:

Ideal Architecture Diagram

This architecture positions the core business functionality in a center tier, protected from backend services (like web services and databases) by abstraction layers organized by topics. On the other side the core business services of the center tier are exposed to the outside world through a single point of access (a service layer). Any consuming components of these core business services (through the service layer) access these services without being known to the center tier.

The main advantages of this ideal architecture have already been described: the architecture envisions a layer of core business services that depends on nothing but a number of abstract backend services — meaning that the layer can be plugged into any service collection that offers the required functionality. At the same many different exposing layers can be hooked into the core business layer, which means that its services can be thrown onto a website using JSPs, JSF, another framework or in a completely different form (like a collection of web services or exposed through JMS).

Going off the rails with session management

An essential part of making the ideal architecture work correctly is in having all aspects of the core functionality in the central layer. And none of it in any other layer (like a front end layer). Now, that sounds obvious; but since it is so important I will say it again: none of the core functionality should be outside the core layer. And this is where the JEE model gets it wrong (in my opinion): the JEE model attaches all session management to the front end technologies [0].

Session management is that part of server side technology that pertains to maintaining state across multiple requests from the same client within a relatively short period of time. Its effect is felt in all sorts of aspects of server side applications, such as maintaining a shopping cart or storing form contents (which is important with regards to the infamous “back-button problem” in web applications). These examples show, by the way, that while some parts of session management actually belong in the center tier because they are part of the core functionality (like shopping cart management) others really do belong in the front end (form contents). Which probably explains why Sun’s JEE platform puts all of it in the front end: when the Enterprise Edition got started, the very visual web front end was all that there was so it seemed to fit together.

In any case, the problem is that having session management based totally in the front end (in the form of the javax.servlet.http.HttpSession, in the case of servlet technology) makes it natural and necessary to pull some functionality from the center layer into the front end. Most shopping cart applications for instance save the “cart” in the front end session (although there are exceptions like Amazon). The result is this:

JEE session architecture

As you can see, there is now a dependency from the center tier business components to the front end component, specifically the session management part. Just to be clear, I’m not saying there will necessarily be a type dependency in your code (although I wouldn’t be surprised if a number of people had dealt with this situation by passing a javax.servlet.http.HttpServletRequest to the business layer and giving the business services direct access to the HttpSession). But the dependency will be there, often in an invisible way: the business services will depend for their operation on the session management in the front end to hold on to domain objects which the front end can receive in one request and pass back to the center tier in the next request. Which is bad, since it (implicitly) binds the center tier to the front end (i.e. to the front end functionality).

In the ideal architecture, the front end layer should obey the simple behavioral pattern of request-format response data-response. Limiting the front end layer to this simple pattern isn’t possible if the center tier relies on session management functionality from the front end — the front end will have to be equipped with knowledge to store domain objects from the center tier in the session and retrieve the correct object from the session at the right time to pass it to the center tier. It also makes it very difficult to connect the center tier to another front end layer (or front end technology), since another front end must provide the same session management functionality in order to allow the enter tier to function correctly.

Doing it another way

What is needed to solve this, I think, is a form of session management that is directly accessible to the business layer. Having session management in the center tier allows you to have session management, yet maintain the independence of the business code from the front end layer (which provides the session management). However, simply making the front end session management directly accessible to the center tier is not a complete solution (you could accomplish that simply by passing the front end session object to the center tier with every call); if you simply export the front end session management to the center tier, you are still binding the two layers to one another.

What is needed is to introduce a session management mechanism into the center tier that is not itself bound to the front end session management mechanism — the center tier should have session management of its own. Doing so maintains the independence of the center tier; the center tier can still be moved from server to server, be plugged into back ends and front ends transparently without binding to them while at the same time allowing the center tier to take all of its functionality with it wherever it goes.

There are, I think, two ways to introduce session management for the business layer:

  1. Use some separate, platform independent library to introduce separate session management for the business layer
  2. Make the front end session management accessible to the business layer through an abstraction layer

A separate library

Introducing separate session management (using a library or possibly a homegrown solution) is probably the most straightforward solution of the two. You plug in a jar and you’ll probably have to refactor the exposed business services so that they always get some sort of token with every request that allows your business layer session management to retrieve the session state uniquely.

The major downsides of this option include that the fact that you will probably be duplicating functionality that is already available on the server and that you will have to expose part of your session management mechanism to the front end (leaving open the possibility of errors, security risks and of course violating the “don’t show your guts” principle of software engineering). But it is simple and portable.

Abstracting the front end session management

The second option is a bit more involved to arrange, but is probably cleaner in the long run: you still make use of the front end session management but in a way that doesn’t bind the business layer to the front end. The way to do this is to expose the front end session management to the center tier in such a way that the center tier has no type dependencies on the front end session management. The architecture looks something like this:

Abstract session management

This architecture introduces an abstract session management component for use by the center tier. This abstract session management component provides access to the session management provided by the front end, but in such a way that the center tier has no type dependency on that session management component. This way, if you move to a front end with a different session management component you don’t have to touch the center tier, just as long as the new session management component has functionality similar to that of the old one.

Trying it out

In order to see if there is any hope for this idea, I tried to implement it myself with a small library. The idea I had was to define two abstract types for use by the center tier (Session and SessionManager) which would provide the business layer with abstract access to session management. In my back-of-a-napkin design the Session represents a session that you can store objects in using a key object (just like in an HttpSession). The SessionManager allows for session management: creating and retrieving Session instances as well as terminating (discarding) existing instances. This should form the core of the “library”:

Session exposer core

As you can see above, Session is an interface; it simply defines a generic type of session and implementations of this interface for a specific session management mechanism should be adapters between specific session classes and the interface defined by this type. The SessionManager on the other hand is an abstract class that also follows the singleton pattern. This allows simultaneously to have specific implementations for each session mechanism necessary (with knowledge on how to get a specific session object) and to make getting hold of a specialized session manager type transparent to the business layer; the getInstance() method in this case makes use of a properties file which contains the name of the specialized session manager to use for the current session management mechanism.

In order to be of practical use this abstract core should be extended with functionality that provides specific implementations for specific session management mechanisms. As a test case I implemented a bridge to the session management mechanism of the JEE platform (embodied by the HttpSession interface).

As described above, the implementation of Session should merely be an adapter, a wrapper class around the HttpSession. As such it is remarkably unspectacular:

class HttpSessionBridge implements Session
{
        /** The actual session. */
        private final HttpSession       realSession;

        /**
         * Constructor.
         * 
         * @param httpSession The real session that this adapter class delegates to.
         */
        protected HttpSessionBridge(final HttpSession httpSession)
        {
                this.realSession = httpSession;
        }

        /**
         * {@inheritDoc}
         */
        public Object clearKey(final Object key)
        {
                if (String.class.isInstance(key))
                {
                        Object currentValue = realSession.getAttribute((String) key);
                        realSession.removeAttribute((String) key);
                        return currentValue;
                } else
                {
                        throw new InvalidSessionAttributeKeyException("Key to clear is not of type String", key);
                }
        }

        /**
         * {@inheritDoc}
         */
        public void clearSession() throws UnsupportedOperationException
        {
                Enumeration keys = realSession.getAttributeNames();
                while (keys.hasMoreElements())
                {
                        String key = (String) keys.nextElement();
                        realSession.removeAttribute(key);
                }
        }

        /**
         * {@inheritDoc}
         */
        public Object getAttribute(final Object key) throws InvalidSessionAttributeKeyException
        {
                if (String.class.isInstance(key))
                {
                        String keyString = (String) key;
                        Object result = realSession.getAttribute(keyString);
                        return result;
                }
                throw new InvalidSessionAttributeKeyException("Key is not a String object", key);
        }

        /**
         * {@inheritDoc}
         */
        @SuppressWarnings("unchecked")
        public SetgetKeys() throws UnsupportedOperationException { Setset = new HashSet(); Enumeration enumeration = realSession.getAttributeNames(); while (enumeration.hasMoreElements()) { set.add(enumeration.nextElement()); } return set; } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") public ListgetValues() throws UnsupportedOperationException { Listlist = new ArrayList(); Enumeration enumeration = realSession.getAttributeNames(); while (enumeration.hasMoreElements()) { list.add(realSession.getAttribute((String) enumeration.nextElement())); } return list; } /** * {@inheritDoc} */ public void setAttribute(final Object key, final Object value) throws InvalidSessionAttributeKeyException, InvalidSessionAttributeValueException { if (String.class.isInstance(key)) { String keyString = (String) key; realSession.setAttribute(keyString, value); } else { throw new InvalidSessionAttributeKeyException("Key is not a String object", key); } } } 

The SessionManager is a lot more interesting. Its role is to provide access to the JEE HttpSession object; since this access is only available through the javax.servlet.http.HttpServletRequest, the session manager must be able to access the request provided by the servlet container. I will return to the question of how this is done a little later.

In order to hold on to the HttpServletRequest and remember which call to the business services belongs to which request (since there may be multiple being handled concurrently) the SessionManager uses a java.lang.ThreadLocal instance. This under the assumption that each request is being handled by a single thread at any given time. This, by the way, is also the major weak spot of my little trial implementation: if the business services spawn internal threads, they will not be able to access the session correctly (or at all).

With the ThreadLocal instance in place, the rest of the SessionManager implementation is straightforward:

public class HttpSessionManager extends SessionManager
{
        /** The store for servlet requests during the lifetime of that request. */
        private static final ThreadLocal<httpservletrequest>    servletRequestStore;

        static
        {
                servletRequestStore = new ThreadLocal<httpservletrequest>();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Session getSession()
        {
                Session session = null;
                HttpServletRequest httpServletRequest = servletRequestStore.get();
                if (httpServletRequest != null)
                {
                        HttpSession httpSession = httpServletRequest.getSession();
                        session = new HttpSessionBridge(httpSession);
                }
                return session;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void terminateSession() throws UnsupportedOperationException
        {
                HttpServletRequest httpServletRequest = servletRequestStore.get();
                if (httpServletRequest != null)
                {
                        HttpSession httpSession = httpServletRequest.getSession(false);
                        if (httpSession != null)
                        {
                                httpSession.invalidate();
                        }
                }
        }

        /**
         * Store the servlet request for use by the session manager.
         * 
         * @param request The servlet request.
         */
        public void storeServletRequest(final HttpServletRequest request)
        {
                servletRequestStore.set(request);
        }

        /**
         * Clear the servlet request from the session manager.
         */
        public void clearServletRequest()
        {
                servletRequestStore.remove();
        }
}

So, this leaves the question of how to get each new HttpServletRequest into the ThreadLocal instance without (obviously) impacting the front end code (JSPs, helper classes, et cetera). To make this happen I used a javax.servlet.ServletRequestListener. This is a type of class (defined in the Servlet specification) that is automatically informed by the servlet container when a servlet receives a request. More specifically it allows you to react when a javax.servlet.ServletRequest comes into scope (reaches a servlet or the start of an associated filter chain) or goes out of scope (leaves a servlet or the last filter of its associated filter chain). In my case I combined a listener with the fact that the session manager is a singleton entity to allow me to put each HttpServletRequest into the ThreadLocal instance as the request came into scope.

public class SessionExposerServletRequestListener implements ServletRequestListener
{

        /**
         * {@inheritDoc}
         */
        public void requestDestroyed(final ServletRequestEvent event)
        {
                HttpSessionManager httpSessionManager = (HttpSessionManager) SessionManager.getInstance();
                httpSessionManager.clearServletRequest();
        }

        /**
         * {@inheritDoc}
         */
        public void requestInitialized(final ServletRequestEvent event)
        {
                HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
                HttpSessionManager httpSessionManager = (HttpSessionManager) SessionManager.getInstance();
                httpSessionManager.storeServletRequest(request);
        }

}

Note that this listener doesn’t just make the session manager aware of requests; it also removes the request once it goes out of scope. There are a number of reasons for doing this. First of all, holding on to an HttpServletRequest that has gone out of scope prevents garbage collection. Second, clearing up the request from our ThreadLocal instance prevents problems with servlet containers that use thread pooling (or other object pooling).

Putting it to the test

Finally, in order to test, I created a simple web application with a single, simple redirect servlet. The application does nothing except allow you to browse from a start page (a state in which the server has no session associated with the servlet request) to a page in which a number of values are read from the session object (which must have been created and filled in the intermediate process). The application demonstrates that a POJO class representing a business service can successfully use my POC library to access the session and place values in it. In addition the application has two paths through the servlet, one which creates a session from the servlet and one in which the session can only be created due to access from the POJO.

The only moderately interesting things in this application are the configuration files. The web.xml is dirt common except for a listener section which hooks the listener class described earlier into the application. In addition there is a properties file which identifies the session manager class to use by name.

Recapping

In this article I’ve explained why I don’t like working on the front end and why I think that the current JEE style of server side session management is a bad idea with regards to maintaining the encapsulation and loose coupling of the business layer. I’ve tried to demonstrate that having session management solely in the front end makes it practically impossible not to bind your business tier to a particular front end (unless your entire application consists of one business service).

In addition to that I’ve discussed what I think would be a better approach and some ways of achieving it. Finally I discussed a small experiment I did as a proof of concept of implementing this approach by abstracting away from a specific type of session management.

Sources

In case anybody is interested in experimenting for themselves, I’ve attached the sources (a couple of Maven 2 projects) here: http://www.gridshore.nl/wp-content/uploads/sessionexposer.zip.


[0]

Okay, not all of it. If you use a stateful session bean that can maintain a lot of state in the business layer. But that means tying yourself to an EJB implementation, plus you still need the front end session management to hold on to your EJB reference.

7 thoughts on “Rethinking session management

  • October 30, 2008 at 2:32 pm
    Permalink

    Hello everybody,

    Allard: I see a session as some temporal data that is stored (typically in memory) for a short period of time, just to remember what the user is doing during his visit. If data has to be stored in memory for two weeks, the JVM is most likely not the right place. And I wouldn’t call two weeks a session anymore, …

    I agree with Allard’s characterization of a session; in fact, I tried to say something similar in the article. What Erik is talking about reaches more into the area of session data persistence. However, I also agree with Allard when he says

    when it is a business requirement to retain a users shopping basket beyond the HTTP session scope, that it has to be built in the business layer,

    Which was part of my point: core business functionality should be in the component responsible for that functionality. Where Jettro/Allard and I don see eye to eye is in the idea that session management should be based exclusively in the front end. Doing so makes it difficult not to blur the distinction between front end and middle tier to the extent that they become one monolithic whole.

    Allard: although I doubt that porting the HttpSession logic to the business layer would be the way to go.

    You’re correct, insofar that the business tier should not be hardlinked to the HttpSession since that is just another way of hardlinking to the front end. That’s why I recommended to use an abstraction layer if you want to reuse the front end session management mechanism. At the same time I want to point out that you don’t have to reuse the front end session mechanism — you can use another mechanism, if you wish (and have one available).

    At the same time I would note that session persistence through an abstraction layer places stronger requirements on the session management component you want to plug in. For example, starting from a JEE mechanism you have a session listener that you can use to persist session data before the session is about to end. But to maintain the abstraction, every other session mechanism you would want to use must then also support such a mechanism.

    Allard,

    Don’t you agree with me that it would have been a lot easier if they let session management to be handled on the client side?

    No, not really. It would have been a lot easier when writing the caching component for those services that Alexander and I added later on (a proxying server), but that’s all. If state management had been on the client side, that would have made a little more work for us (Allard, I and the rest of the original team) but not very much. On the other hand, if you look at what the provider was doing, it would have been thoroughly impossible for them to place state management on the client side; for them, it was (and is) far more valuable to consider their services to be a black box pluggable component as I describe in the article.

    BTW, I’ve been thinking a bit about your previous reply. The thought occurs to me that what we are talking about touches upon the difference between an “application” and a “service component” — the difference between an “end of the line” component with a small number of related purposes and a collection of smaller, more open-ended components which are meant to be pieces of a larger whole. That same difference of course has its repercussions as well for the responsibility of session management.

    Reply
  • October 30, 2008 at 9:10 am
    Permalink

    Hi all,

    Erik said “Image that, a HTTP session that runs for 2 weeks!”. Isn’t that exacly the sort of thing Ben is trying to do? I see a session as some temporal data that is stored (typically in memory) for a short period of time, just to remember what the user is doing during his visit. If data has to be stored in memory for two weeks, the JVM is most likely not the right place. And I wouldn’t call two weeks a session anymore, since you’re long gone.

    And Ben, I do remember the stateful webservices that we had to consume. Don’t you agree with me that it would have been a lot easier if they let session management to be handled on the client side?

    I agree with Jettro that when it is a business requirement to retain a users shopping basket beyond the HTTP session scope, that it has to be built in the business layer, although I doubt that porting the HttpSession logic to the business layer would be the way to go.

    Reply
  • October 29, 2008 at 7:59 pm
    Permalink

    It al has to to with naming, what is a session. When keeping things of a shopping cart on the server, are we talking about a session? Is that a temporary state? Storing items in a database with some time based triggers on it could be called a session as well. To me what Erik tells is just a business requirement, does not have anything to do with m understanding of a session. You just try to get back potential buyers (excellent way though).

    I was thinking about rich clients as well, thinking about what state to keep where. Flex has a different kind of model than a normal web application. With flex I tend to store more things in the client than I used to. I used to store more in the session, in that case the web session. Does that mean we have a session on the client now, yes I think so. If I than relate back to the t-shirt example and add cookies in the game. Than you can present unfinished order to your visitor from the contents of it’s cookies. Yes I know there is less control then.

    Interesting topic, to me it is just about naming, the idea of bringing a session to the core business does not appeal to me. I’d like to talk about business requirements. If these requirements need temporal state, you need to find a solution. Maybe taking in the HttpSession is not that bad, than you have to make sure you loosely couple your actual front end. I am thinking about two projects we are doing in JTeam with a server application exposing there content in JSON as a kind of webservice or REST like api. The php/flash front ends use these services and JSON and can even handle there own session. Than we have a php session and a java session. Maybe we can call the java session in that case integrated with the business logic, maybe it is just a different view. You tell me.

    Again interesting topic, thanks Ben

    Reply
  • October 29, 2008 at 7:28 pm
    Permalink

    Hi Ben,
    Just scanned the article (i am in the USA for business) but immediatly our ISIS Papyrus architecture came to my mind.
    Within ISIS Papyrus everything is centered around the concept of Roles and Policies. ROLE: defines the privileges and methods authorized for this user. POLICY: defines the policy that a user/agent must have to be allowed to access this instance of a class.
    Furthermore we have of course USERS. And now it comes, Applications are assigend to Users and what they can do and view depends of course on their Role and Policy. But now it comes, as the application is assigned (by Reference) to a User and we are storing the session-data for that User and that Application. We can even share our session with another user e.g. help desk employee to allow him to see or even take over the session (sharing the screen). the Application can run in any browser (flash-plugin) or as fat-client with 100% identical look & Feel as the application definition contains also the UI definitions. It goes even further, I can make runtime changes to the UI and immediatly all views (browser and fat-client) will be updated by the system (proxy push).

    enfin, i think you are right. thats what i wanted to say

    Good work

    Reply
  • October 29, 2008 at 4:55 pm
    Permalink

    I recently added some t-shirts to the shopping basket on threadless.com. As I was still doubting I did not actually buy any. To my pleasant surprise, I got an email 2 weeks later that the t-shirt that I added to the shopping basket was about to run out of stock.

    Image that, a HTTP session that runs for 2 weeks! No I think session management in the center layer is an excellent idea.

    Reply
  • October 29, 2008 at 1:09 pm
    Permalink

    Hey Allard,

    It seems to me we’re starting from two different vantage points. In my case I’m starting from the point of view that an application core should be an API-like thing, a black box with swappable front ends and back end plugs and with complete mastery of its own functionality. Your point of view of an application is more of an old telephone switch board: not a unified whole at all but rather individual services which an external entity has to plug into one at a time and which just happen to be taped together in the shape of a big block. In other words, the two of us are making different choices with respect to granularity. Which of course have different consequences for the placement of process control.

    It also depends a bit on what you want exactly. What I see as the ideal architecture is a thing that can easily be plugged into different front ends. In the case of your choice, it requires a little more work. Both are possible; I’m sure you recall our working together on a project to connect to a web service provider whose services were NOT stateless. ;-)

    Isn’t architecture wonderful, with all its possibilities? :-)

    Reply
  • October 29, 2008 at 8:56 am
    Permalink

    Hi Ben,

    very nice article, but I tend to disagree with the contents. I do beleive that session management should be bound to the frontend layer. I’ll try to explain why.

    The core business layer does not know of anything beyond the JVM. Any object returned by the core business layer resides in this JVM. Depending on the type of frontend this object should either remain there (in a session, for example), or be sent to the client and discarded. In Web Services world interaction is often stateless. The client (e.g. a desktop application consuming the web services) will maintain the state over several requests, until some “do” service will actually save the changes. In case of an MVC frontend, this is different. It is not always a good option to maintain the entire state inside the web browser, since it might require too much traffic. This case could require the state to be stored inside the frontend layer.

    Let’s relate to the shoppingcart example. The core business services would typically contain operations to retrieve certain product details and an operation to submit an order. Submitting an order would require the client to submit all the items to order, as well as some shipping details. Where this list of products comes from shouldn’t really matter. In case of a web browser, it probably comes from a session. In case of web services, this list is probably supplied directly inside the XML request.

    Why would you force your frontend to do several requests to your core business layer in order to set up a certain session state before committing this state?

    Just my 2 cents.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>