SessionMan gives a solution to the problem of saving state while using web-services

The problem

"By design, Web services are said to be stateless..." – this statement says a lot. It means that you will have no problems passing the code of a city to the server to retrieve weather forecast for the next week. But to organize a client-bank system with the usage of Axis2*, you’ll have to work for a while, because such systems assumes authorization procedure and supporting of a session, created for a user, for some time period.

Note
*Axis2 – second generation of the most popular web-services engine, developed under the aegis of Apache Software Foundation.

Possible solutions of the problem under the Axis2 platform

The search of the solution to this problem has leaded me to some article [1]where IBM folks proposed their own solution. To make the long story short, they have proposed to add to the service-class, generated by Axis2 a static HashMap field, which would behave as a storage of the users’ session information. And WSDL services would contain two additional operations: login and logout.

Everything seems to work fine, though there is one small problem, or, we should rather call it a “restriction”. The user should explicitly call the “logout” method, otherwise information of the session while be alive till the next server reload and the HashMap will be the source of memory leaks and performance problems.

We propose you a solution to this restriction: open source SessionMan, library, providing you with the basic functionality to work with sessions in any Java-based server application. It provides you with the comfortable api to work with sessions, including the periodic garbage collection (which consists in cleaning the expired sessions).

To run the SessionMan, usage example, you should have TomCat and Axis2. It it’s needed, you may install TomCat and Axis2 using their installation notes and we may continue.

WSDL – core part of any web-service

The first step of our job is to create a wsdl-document, describing our future web-sercice:

        
        <portType name="SessionManExamplePort">
                <operation name="login">
                        <input name="loginOpIn" message="tns:loginSoapMessage" />
                        <output name="loginOpOut" message="tns:sessionSoapMessage" />
                </operation>
                <operation name="disconnect">
                        <input name="disconnectOpIn" message="tns:sessionSoapMessage"/>
                        <output name="disconnectOpOut" message="tns:isOkSoapMessage" />
                </operation>
                <operation name="ping">
                        <input name="pingOpIn" message="tns:sessionSoapMessage" />
                        <output name="pingOpOut" message="tns:pingSoapMessage" />
                </operation>
        </portType>
        
        

As we can see from this wsdl fragment, our web-service will consist of three operations: login, disconnect** and ping. First operation will have SOAP envelop, wrapping user’s login and password, as the input data.

        
        <xsd:element name="UserAuthElement">
                <xsd:complexType>
                        <xsd:sequence>
                                <xsd:element name="login" type="xsd:string" minOccurs="1" maxOccurs="1"/>
                                <xsd:element name="password" type="xsd:string" minOccurs="1" maxOccurs="1" />
                        </xsd:sequence>
                </xsd:complexType>
        </xsd:element>
        
        

The latter two receive SOAP envelop, wrapping only session id, which is on one hand needed to check the session’s validity before executing any operation, on the other hand, it is quite enough to for the SessionMan’s example.

After the WSDL-document is created, we laungh the wsdl2java tool, which is a part of Axis2 and what until it generates all the classes needed.

Fully functional example of working with SessionMan library jointly with Axis2 could be downloaded from the following svn repository: http://sessionman.googlecode.com/svn/trunk/sessionman-example.

Instruction of working and building the product for Eclipse 3.2 environment could be found here: http://sessionman.googlecode.com/svn/trunk/sessionman-example/readme.txt.

Note
**method’s name was chosen not accidentally, as in one of previous Axis2 v.1.0 versions there were some bus with usage the “logout” name for a method.

SessionMan comes

wsdl2java will generate a whole package of classes, one of which will have the following name SessionManExampleServiceSkeleton – a heart of our future service. For the future work we should inherit this class and create our own SessionManExampleService.

Connecting SessionMan:

            import com.webtair.session.*;
            import com.webtair.session.artifact.*;
            import com.webtair.sessionman.ws.types.*;
        

Adding our sessions handler to the class:

        
        public class SessionManExampleService extends
                SessionManExampleServiceSkeleton {

                ... 
                /** SessionMan instance - main goal of this example */
                private static SessionMan<SimpleSessionInfo> sessions
                        = new SessionMan<SimpleSessionInfo>();
        
        

Some clarifications are needed there:

  1. Class com.webtair.session.SessionMan has two constructors: public SessionMan(ConfigBean config) and public SessionMan() - the latter creates an instance of the SessionMan with the default configuration (session’s lifetime is 30 min and time period to clean expired sessions is 10 min). The former constructor allows the user to provide SessionMan with his/her own configuration. To see full configuration properties please see com.webtair.session.config.ConfigBean
  2. Any class, which implements com.webtair.session.artifact.SessionInfo interface could be used as the storage of session’s inforation, SimpleSessionInfo is the default realization of this interface, it contains only basic operations.

Thus, if you need to create a storage for, say, the state of a user’s basket, you could simply create some realization of SessionInfo interface with such functionality and use it in SessionMan.

So, we create a session and return it to the web-service’ client.

        
        /**
         * Method that allow for client to login under this ws
         * @return IdSessionDocument - soap envelope with session id;
         */
        @Override
        public IdSessionDocument login(UserAuthElementDocument userAuthElementDocument) { 
         /* default login and pass for examples only. At this place you 
         * mast recieve real pass from the real storage like RDBMS or 
         * config-file or somthing else.
         */
         String defaultLogin = "sessionman";
         String defaultpass = "example";

         UserAuthElement userAuthElement = userAuthElementDocument.getUserAuthElement();

         if (userAuthElement.getLogin().equals(defaultLogin)
                && userAuthElement.getPassword().equals(defaultpass)){

                // request for id session from SessionMan lib 
                 idSession = sessions.putSessionInfo(userAuthElement.getLogin(),
                new SimpleSessionInfo());
         }
         ...
        }
        
        

The crucial part of retrieving the session’s id is putSessionInfo() method, which puts the SessionInfo controller to the HashMap and returns the unique session’s id.

Checking if session is alive:

validateSession(String idSession) method allows not only to check if the session is expired or not, but it also refreshes its last usage time, automatically prolonging its life time for the value, stated in the ConfigBean (30 min is the default one).

Calling isSessionExpired(String idSession) method simply returns the information if the session is alive, without any refreshing.

LogOut and sessions cleaning

If the user has not done the explicit disconnect(logout) (via calling the corresponding method), the session will be killed by the background thread, sleeping for the time interval, stated in ConfigBean and then locking and cleaning the HashMap.

Concluding remarks

Fully functional example of working with SessionMan library jointly with Axis2 could be downloaded from the following svn repository: http://sessionman.googlecode.com/svn/trunk/sessionman-example.

Resources

  1. Online banking with Apache Geronimo and Axis2: http://www-128.ibm.com/developerworks/edu/os-dw-os-ag-onbank1.html;
  2. WebTair SessionMan library: http://www.webtair.com/sessionman;
  3. Example for SessionMan and Axis2:http://sessionman.googlecode.com/svn/trunk/sessionman-example;
  4. SessionMan online API JavaDoc: http://www.webtair.com/sessionman/api/index.html.

Vyacheslav Yakovenko, Dmitry Rudenko,
webtair.com