Q: So does Axis support sessions?
A: Yes. We have a session abstraction which allows an extensible set of underlying implementations - take a look at the class org.apache.axis.session.Session for details. In particular, we currently support sessions based on HTTP cookies and also transport-independent sessions based on SOAP headers. It is up to some handler on the request chain to set up an appropriate Session implementation and attach it to the MessageContext with MessageContext.setSession() so that anyone who wants to use session semantics can get at it.
Q: Cool, SOAP header-based sessions? How do I make that work?
A: There is a Handler class called "org.apache.axis.handlers. SimpleSessionHandler " which implements this functionality. You need to include this handler in the request and response flows of both your client and your server. Take a look at our session test ( test.session.TestSimpleSession ) for an example. Regarding use in clients, look at AxisClientConfiguration.
Q: What else can I do with sessions?
A: Any time after the session context has been established, calling getSession() on the current messageContext will obtain you a reference to a Session object. You may use this object like a Hashtable to store arbitrary data associated with this Session. For instance, on one request you might extract the caller's name and address from a database (an expensive operation), and then cache them in the Session object for fast access on subsequent invocations from the same caller. This functionality can be used either by custom Handlers or by your backend service object itself.
Q: Is it standard to maintain a SOAP session with HTTP Cookies ?
As SOAP is transport agnostic, using HTTP cookies to maintain a session is not part of the standard. However, HTTP Cookies is the most widely used method to maintain session during SOAP calls and it has been integrated in the WS-I Basic Profile 1.0 Specification. This reduces the interoperability problems.
Most of the SOAP implementations (Apache Axis, IBM Websphere, .Net, ...) support it.
To conclude, it is not exactly a standard but it is a de facto standard.
Extract from WS-I Basic Profile 1.0 Specification :
4.3.10 HTTP Cookies
R1120 An INSTANCE MAY use the HTTP state mechanism ("Cookies").
R1122 An INSTANCE using Cookies SHOULD conform to RFC2965.
R1121 An INSTANCE SHOULD NOT require consumer support for Cookies in order to function correctly.
R1123 The value of the cookie MUST be considered to be opaque by the CONSUMER.
The Profile recommends that cookies not be required by instances for proper operation; they should be a hint, to be used for optimization, without materially affecting the execution of the Web service. However, they may be required in legacy integration and other exceptional use cases, so requiring them does not make an instance non-conformant. While Cookies thus may have meaning to the instance, they should not be used as an out-of-bound data channel between the instance and the consumer. Therefore, interpretation of Cookies is not allowed at all by the consumer - it is required to treat them as opaque (i.e., have no meaning to the consumer).
Q: How can I read the session cookie ?
Http Cookies are hold after the invocation by the MessageContext properties HTTPConstants.HEADER_COOKIE and HTTPConstants.HEADER_COOKIE2.
Sample to display the cookies :
// Enable client side session binding.setMaintainSession(true); // Invoke service binding.aMethod(); // Read Cookies MessageContext messageContext = binding._getCall().getMessageContext(); String cookie1 = (String) messageContext.getProperty(HTTPConstants.HEADER_COOKIE); String cookie2 = (String) messageContext.getProperty(HTTPConstants.HEADER_COOKIE2); System.out.println("cookie1 : '" + cookie1 + "'"); System.out.println("cookie2 : '" + cookie2 + "'");
Sample of result :
cookie1 : 'JSESSIONID=FEC9990323740BFD0FECF965F1BCC09A' cookie2 : 'null'
Sample of client side sessions
To enable stateful invocations on the client, you have to call setMaintainSession(true) on the Stub
HelloWorldServiceLocator helloWorldServiceLocatorForJohnDoe = new HelloWorldServiceLocator(); HelloWorldBindingStub bindingStubForJohnDoe = (HelloWorldBindingStub) helloWorldServiceLocator.gethelloWorldBinding(); bindingStubForJohnDoe.setMaintainSession(true); // Say hello will create a server side session String helloJohnDoe = bindingStubForJohnDoe.sayHello("JohnDoe"); System.out.println("helloJohnDoe : " + helloJohnDoe); // Say good bye will use the same server side session String goodByeJohnDoe = bindingStubForJohnDoe.sayGoodBye("JohnDoe"); System.out.println("goodByeJohnDoe : " + goodByeJohnDoe);
Client side session support relies on http cookies, all the cookies created by the server (Set-Cookie header in the http response) are kept by the client and re-sent for each following invocation.
- That is to say not only the JSESSIONID cookie is propagated but also any other cookie (e.g. : created by an SSO layer, ...)
The internal behavior of client side session support is to store the cookies as an instance variable of the ServiceLocator (via the AxisEngine)
Sample of multi client side sessions
A SOAP client may have to open several sessions at the same time. To do this, you have to instantiate one ServiceLocator/Stub per session.
Axis supports multi client side sessions with an important restriction : you must instantiate one ServiceLocator per session (ie per Stub).
Sample of mixed invocations :
HelloWorldServiceLocator helloWorldServiceLocatorForJohnDoe = new HelloWorldServiceLocator(); HelloWorldBindingStub bindingStubForJohnDoe = (HelloWorldBindingStub) helloWorldServiceLocatorForJohnDoe.gethelloWorldBinding(); bindingStubForJohnDoe.setMaintainSession(true); HelloWorldServiceLocator helloWorldServiceLocatorForJohnSmith = new HelloWorldServiceLocator(); HelloWorldBindingStub bindingStubForJohnSmith = (HelloWorldBindingStub) helloWorldServiceLocatorJohnSmith.gethelloWorldBinding(); bindingStubForJohnSmith.setMaintainSession(true); // Open the JohnDoe session String helloJohnDoe = bindingStubForJohnDoe.sayHello("JohnDoe"); System.out.println("helloJohnDoe : " + helloJohnDoe); // Open the JohnSmith session String helloJohnSmith = bindingStubForJohnSmith.sayHello("JohnSmith"); System.out.println("helloJohnSmith : " + helloJohnSmith); // Reuse the JohnDoe session String goodByeJohnDoe = bindingStubForJohnDoe.sayGoodBye("JohnDoe"); System.out.println("goodByeJohnDoe : " + goodByeJohnDoe); // Reuse the JohnSmith session String goodByeJohnSmith = bindingStubForJohnSmith.sayGoodBye("JohnSmith"); System.out.println("goodByeJohnSmith : " + goodByeJohnSmith);
The ServiceLocator is a heavyweight object that holds the HTTPSender. However, as the ServiceLocator holds the session data (the cookie), it can not be shared by several Stubs.
Q: Is it possible to maintain a session for a long duration with Axis Client ?
It can be necessary to maintain a web service session for a long duration (e.g. between two user interactions).
Maintaining the session between SOAP invocations requires to keep a reference on the client Stub. The Stub is a lightweight component that can be kept alive for a long time.
Note that the Stub is lightweight in the sense that :
- It has small memory footprint. It only holds headers and attachments.
Attachments are automatically removed calling Stub.getAttachments() and thus should never live for a long duration on the Stub
It does not hold critical resources (socket, ...). It is the ServiceLocator and not the Stub that may hold opened http connections (see FrontPage/Axis/AxisCommonsHTTP )
Note that maintaining multi client sessions for a long duration is more complex because ServiceLocator can not be reused. You must instantiate one ServiceLocator per session (ie per Stub). Due to this, the memory footprint will be much more important. In suc a case, using the CommonsHTTPSender instead of the HTTPSender will add a big overweight.