Maintaining Sessions using JAX-WS 2.0

This techtip will focus on how to develop a webservice client and server application that maintains session state from one client invocation to the next. This is usefull for webservice application writers that need to develop applications that maintain state across client invocations. A classic example is a shopping cart application.

The example code below was developed and tested using a GlassFish implementation.

Developing a Web Service to maintain session state across client invocations

Step 1

Develop an annotated web service implementation Java class.

Below is a simple example of a web service that maintains the session IDs for all clients connecting to its service. Client session IDs are stored and looked up in a HashSet initialized within its Constructor. In order to determine the session ID of our client the web service needs access to the WebServiceContext which is injected into the endpoint implementation class using the @Resource annotation. Next the endpoint code gets access to the HttpServletRequest object from the MessageContext of the client request in order to determine the session ID for this client invocation. If the session ID exists we know we are in the same session; otherwise this is a new session and the ID is stored in the HashSet appropriately. The web service method printSessionInfo shows the details of this interaction.


/\*
 \* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 \* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 \*/
package jaxws.j2w.document.literal.sessionmaintain.server;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import javax.jws.WebMethod;
import javax.jws.WebService;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;

import javax.xml.ws.handler.MessageContext;

import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceContext;

@WebService(
    name="Test",
    portName="TestPort",
    serviceName="TestService",
    targetNamespace="http://test.org/wsdl"
)
public class TestImpl {

    @Resource private WebServiceContext wsc;

    private Set clients;	// For storing our session ids from clients

    private String getClientID() {
        HttpServletRequest req = (HttpServletRequest)
            wsc.getMessageContext().get(MessageContext.SERVLET_REQUEST);
        HttpSession session = req.getSession();
        return session.getId();
    }

    public TestImpl() {
        clients = new HashSet();
    }

    @WebMethod
    public String printSessionInfo() {
	System.out.println("endpoint invoked, checking session id of client");
        String id = getClientID();
        System.out.println("\*\* looking up session id: " + id);
	boolean idExists = clients.contains(id);
	if (idExists) {
            System.out.println("\*\* found session id: " + id);
	    return "Same session, id is " + id;
	}
	else {
            System.out.println("\*\* storing session id: " + id);
	    clients.add(id);
	    return "New session, id is " + id;
	}
    }
}

Step 2

Next the developer compiles the annotated web service class and uses the wsgen tool to perform the Java-to-WSDL mapping to generate the portable artifacts. The wsgen tool has both a command line interface as well as an ant task provided. Our build scripts use the ant task.

Typing the following will compile the annotated server implementation class and invoke wsgen on this class to generate all the portable artifacts:


$ ant compile-server-j2w

compile-server:
     [echo] compile-server
    [javac] Compiling 1 source file to /tmp/sessionmaintain/classes

do-java2wsdl:
     [echo] Invoking WsGen task (Java-to-WSDL mapping)
    [wsgen] command line: wsimport /files/java/jdk1.5/jdk1.5.0_06/jre/bin/java -classpath /files/java/jdk1.5/jdk1.5.0_06/lib/tools.jar:/sun/appserver9/lib/javaee.jar:/sun/appserver9/lib/appserv-ws.jar:/tmp/sessionmaintain/classes com.sun.tools.ws.WsGen -d /tmp/sessionmaintain/classes -keep -wsdl -r /tmp/sessionmaintain/src/jaxws/j2w/document/literal/sessionmaintain/wsdl -s /tmp/sessionmaintain/generated -verbose jaxws.j2w.document.literal.sessionmaintain.server.TestImpl
    [wsgen] Note:       ap round: 1
    [wsgen] [ProcessedMethods Class: jaxws.j2w.document.literal.sessionmaintain.server.TestImpl]
    [wsgen] [should process method: printSessionInfo hasWebMethods: true ]
    [wsgen] [endpointReferencesInterface: false]
    [wsgen] [declaring class has WebSevice: true]
    [wsgen] [returning: true]
    [wsgen] [WrapperGen - method: printSessionInfo()]
    [wsgen] [method.getDeclaringType(): jaxws.j2w.document.literal.sessionmaintain.server.TestImpl]
    [wsgen] [requestWrapper: jaxws.j2w.document.literal.sessionmaintain.server.jaxws.PrintSessionInfo]
    [wsgen] [ProcessedMethods Class: java.lang.Object]
    [wsgen] jaxws/j2w/document/literal/sessionmaintain/server/jaxws/PrintSessionInfo.java
    [wsgen] jaxws/j2w/document/literal/sessionmaintain/server/jaxws/PrintSessionInfoResponse.java
    [wsgen] Note:       ap round: 2
    [wsgen] [completing model for endpoint: jaxws.j2w.document.literal.sessionmaintain.server.TestImpl]
    [wsgen] [ProcessedMethods Class: jaxws.j2w.document.literal.sessionmaintain.server.TestImpl]
    [wsgen] [should process method: printSessionInfo hasWebMethods: true ]
    [wsgen] [endpointReferencesInterface: false]
    [wsgen] [declaring class has WebSevice: true]
    [wsgen] [returning: true]
    [wsgen] [WebServiceReferenceCollector - method: printSessionInfo()]
    [wsgen] [ProcessedMethods Class: java.lang.Object]

compile-server-j2w:
     [echo] compile-server-j2w

The following classes were generated:

/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/server/jaxws/PrintSessionInfo.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/server/jaxws/PrintSessionInfoResponse.class

Step 3

Next the developer packages the web.xml, service implementation class, and all the generated portable artifacts within a WAR file ready for deployment to a web container.

Typing the following will create and package up all these artifacts in a WAR file:


$ ant create-war 
Buildfile: build.xml

create-war:
     [echo] create-war
     [echo] Creating war file /tmp/sessionmaintain/dist/jaxws/j2w/document/literal/sessionmaintain/J2WDLSESSIONMAINTAIN.war
    [mkdir] Created dir: /tmp/sessionmaintain/dist/jaxws/j2w/document/literal/sessionmaintain
      [war] Building war: /tmp/sessionmaintain/dist/jaxws/j2w/document/literal/sessionmaintain/J2WDLSESSIONMAINTAIN.war
     [echo] Created war file /tmp/sessionmaintain/dist/jaxws/j2w/document/literal/sessionmaintain/J2WDLSESSIONMAINTAIN.war

BUILD SUCCESSFUL

Step 4

Deploy the war file to your GlassFish application server.

Typing the following will deploy this war to your GlassFish appserver:


$ ant deploy
Buildfile: build.xml

checkPlatform:

configUnix:

configWindows:

filter.password.file:
     [copy] Copying 1 file to /tmp/sessionmaintain/build

configPlatform:

deploy:
     [echo] deploy
     [echo] Deploying /tmp/sessionmaintain/dist/jaxws/j2w/document/literal/sessionmaintain/J2WDLSESSIONMAINTAIN.war.
     [echo] asadmin deploy --user admin --passwordfile /tmp/sessionmaintain/build/password.txt --host localhost --port 4848 --contextroot J2WDLSESSIONMAINTAIN --target server --updload=true
     [exec] Command deploy executed successfully.

BUILD SUCCESSFUL

Step 5

Verify web service application is deployed:

In your browser go to URL location of the published WSDL for this server:

This location is as follows:


o http://host:port/J2WDLSESSIONMAINTAIN/jaxws/Test?WSDL

where (host and port) are the settings of your configured GlassFish web server, (J2WDLSESSIONMAINTAIN) is the context root of your web service application, (/jaxws/Test) is the URL alias specified in the web.xml deployment descriptor for deployed endpoint and (?WSDL) is how the published WSDL is accessed.

A WSDL should be displayed if the service is up and running.

Developing a Client to maintain session state across client invocations

Client development always starts from WSDL. The WSDL can be obtained either statically or from a deployed web service. The steps involved:

  1. Run wsimport to generate client-side artifacts pointing to WSDL
  2. Implement the client to invoke the web service
  3. Verify client can access the web service

Step 1

Typing the following will invoke wsimport to import the wsdl and generate all the portable artifacts:


$ ant import-wsdl-client

Buildfile: build.xml

import-wsdl-client:

init:

do-wsdl2java:
     [echo] Invoking WsImport task (WSDL-to-Java mapping)
 [wsimport] command line: wsimport /files/java/jdk1.5/jdk1.5.0_06/jre/bin/java -classpath /files/java/jdk1.5/jdk1.5.0_06/lib/tools.jar:/sun/appserver9/lib/javaee.jar:/sun/appserver9/lib/appserv-ws.jar:/tmp/sessionmaintain/classes com.sun.tools.ws.WsImport -d /tmp/sessionmaintain/classes -keep -s /tmp/sessionmaintain/generated -verbose wsdl/TestService.wsdl -wsdllocation http://localhost:8001/J2WDLSESSIONMAINTAIN/jaxws/Test?WSDL -b /tmp/sessionmaintain/src/jaxws/j2w/document/literal/sessionmaintain/wsdl/customfile-client.xml -b /tmp/sessionmaintain/src/jaxws/j2w/document/literal/sessionmaintain/wsdl/customfile2-client.xml
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/ObjectFactory.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfo.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfoResponse.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/Test.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/TestService.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/package-info.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/ObjectFactory.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfo.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfoResponse.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/Test.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/TestService.java
 [wsimport] jaxws/j2w/document/literal/sessionmaintain/client/package-info.java

BUILD SUCCESSFUL


The following classes were generated:

/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/package-info.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/ObjectFactory.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfoResponse.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/PrintSessionInfo.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/Test.class
/tmp/sessionmaintain/classes/jaxws/j2w/document/literal/sessionmaintain/client/TestService.class

Step 2

The developer next implements the client to invoke the web service and compiles it.

Below is a simple example of a web service client that enables our session state to be maintained. Once we get access to the port we get the BindingProvider for the port to get access to the Request context. The client must set the BindingProvider.SESSION_MAINTAIN_PROPERTY to true in order for the session to be maintained. In the method printSessionInfo we print out the session info before this property is set and after to show that the session ID is now being maintained after being set to true.


/\*
 \* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 \* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 \*/

package jaxws.j2w.document.literal.sessionmaintain.client;

import javax.xml.ws.WebServiceRef;
import javax.xml.ws.BindingProvider;
import java.util.Map;

public class Client {
        
        @WebServiceRef
        static TestService service;

	Test port;

        private Test getPort()
        {
            System.out.println("Obtain port from service");
	    port = service.getPort(Test.class);
	    return port;
	}

        public static void main(String[] args) {
            try {
                Client client = new Client();
		client.getPort();
                client.printSessionInfo();
            } catch(Exception e) {
                e.printStackTrace();
            }
       }

       public void printSessionInfo() {
            try {
		System.out.println("SESSION_MAINTAIN not set all session ids are new");
	        System.out.println(port.printSessionInfo());
	        System.out.println(port.printSessionInfo());
		System.out.println("Invoking printSessionInfo operation ...");
                Map requestContext =
                    ((BindingProvider) port).getRequestContext();
                requestContext.put(
                    BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
		System.out.println("SESSION_MAINTAIN is set all session ids are same");
	        System.out.println(port.printSessionInfo());
	        System.out.println(port.printSessionInfo());
            } catch(Exception e) {
                e.printStackTrace();
            }
       }
}

Type the following to compile the client:


$ ant compile-client
Buildfile: build.xml

init:

compile-client:
     [echo] compile-client
    [javac] Compiling 1 source file to /tmp/sessionmaintain/classes

BUILD SUCCESSFUL

Step 3

Next you can call the runclient task which will deploy the client in the appclient container and run the test.


 $ ant runclient
Buildfile: build.xml

checkPlatform:

configUnix:

configWindows:

filter.password.file:
     [copy] Copying 1 file to /tmp/sessionmaintain/build

configPlatform:

runclient:
     [echo] runclient jaxws.j2w.document.literal.sessionmaintain.client.Client
     [exec] Obtain port from service
     [exec] SESSION_MAINTAIN not set all session ids are new
     [exec] New session, id is 87ced76174257f2a0ed41297882be
     [exec] New session, id is 87ced8381c2b3fed91860384a976
     [exec] Invoking printSessionInfo operation ...
     [exec] SESSION_MAINTAIN is set all session ids are same
     [exec] New session, id is 87ced87dbef27438391f7db4c2b5
     [exec] Same session, id is 87ced87dbef27438391f7db4c2b5

BUILD SUCCESSFUL

As you can see from the output above before the SESSION_MAINTAIN_PROPERTY was set the session ID was new for each invocation. Once we set SESSION_MAINTAIN_PROPERTY to true only the first invocation is new and subsequent invocations return same session ID.

Running the Sample Code

A sample package accompanies this tip. It provides an example that demonstrates the techniques covered in the tip. The sample package includes the source code for the example, required descriptor files, and build scripts.

Code for the sample after extracting its contents is under:

  • sessionmaintain/src/jaxws/j2w/document/literal/sessionmaintain

For a working example of this client and server sample code download here.


Steps to install and run the sample:

Step  1. Download GlassFish from the GlassFish Project page.

Step  2. Set the following environment variables:

          ANT_HOME  - path to location of Ant installation. This example uses Ant 1.6.5.
          JAVA_HOME - path to location of JDK5.0 installation.

         Also, add the Ant location to your PATH environment variable.

Step  3. Download the sample package and extract its contents.

	To get started using this tech tip all you have to edit is the
	following file:
	
	o sessionmaintain/build/common.properties
	
	The main properties to set are the ones below based on your
	GlassFish installation properties. You can check any others
	that may need tweeking based on your setup.
	
	<!-- Main Properties to Set -->
	<!-- Only these need be set -->

	<property name="jdk.home" value="/files/java/jdk1.5/jdk1.5.0"/>
	<property name="appserver.home" value="/sun/appserver9"/>
	<property name="tests.home" value="/tmp/sessionmaintain"/>
	<property name="webserver.host" value="localhost"/>
	<property name="webserver.port" value="8001"/>

Step  4. Start the GlassFish Application Server 

Step  5. cd sessionmaintain/src/jaxws/j2w/document/literal/sessionmaintain

Step  6. Type the following to build, deploy and run the sample:

         ant
Comments:

nn

Posted by guest on August 07, 2006 at 01:13 AM EDT #

Great!......It is very help ful for me..

Thank you.....................

Posted by Kalaiselvan on November 01, 2007 at 11:11 PM EDT #

It is possible also by using @HttpSessionScope and writing less code.

let's see

http://weblogs.java.net/blog/2006/10/17/bringing-state-back-web-services-httpsession-scope

Posted by maintaining jax-ws session state on October 25, 2009 at 10:23 PM EDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

artfish

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today