5 Replies Latest reply on Aug 17, 2010 1:43 AM by Anand Jayaraman

    How to share session between web service calls?

    Anand Jayaraman Newbie

      Hi ,

       

      I am using Jboss CXF for development.

       

      I would like to maintain session state across web service calls.

       

      From CXF client stubs you can maintain session state but it holds only for calls made from that specific client proxy(say CP1). If i want to maintain the same session state across client proxies there is no straight forward way in CXF.

       

      I was able to use HttpConduit and get cookies from it and copy it before next invocation. Something like:

       

      HTTPConduit conduit1 = (HTTPConduit)ClientProxy.getClient(p1).getConduit(); HTTPConduit conduit2 = (HTTPConduit)ClientProxy.getClient(p2).getConduit(); conduit2.getCookies().putAll(conduit1.getCookies());

      Can some one tell me if there is a better way of acheiving this using a configuration change than using copying cookies?

      Regards,

      Anand

        • 1. Re: How to share session between web service calls?
          Jim Ma Apprentice

          Yes. You can use  BindingProvider.SESSION_MAINTAIN_PROPERTY to do this job in CXF.

          Here is some code example from CXF code base . Hope it can help .

          Greeter greeter = service.getGreeterPort();

           

          BindingProvider bp = (BindingProvider)greeter;

                             bp.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

           

           

          Map<String, List<String>> headers= CastUtils.cast((Map)bp.getRequestContext().get("javax.xml.ws.http.request.headers"));

           

          if (headers == null) {

              headers = new HashMap<String, List<String>>();

              bp.getRequestContext().put("javax.xml.ws.http.request.headers", headers);

          }

           

          List<String> cookies = Arrays.asList(new String[] {"a=a", "b=b"});

          headers.put("Cookie", cookies);

           

          String greeting = greeter.greetMe("Bonjour");

           

          • 2. Re: How to share session between web service calls?
            Anand Jayaraman Newbie

            Hi,

             

            I needed one clarification, will this work if there are two separate instances of BindingProvider being used from client code. For e.g.

             

            Greeter greeter = service.getGreeterPort();

             

            BindingProvider bp = (BindingProvider)greeter;

                               bp.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

             

             

            Map<String, List<String>> headers= CastUtils.cast((Map)bp.getRequestContext().get("javax.xml.ws.http.request.headers"));

             

            if (headers == null) {

                headers = new HashMap<String, List<String>>();

                bp.getRequestContext().put("javax.xml.ws.http.request.headers", headers);

            }

             

            List<String> cookies = Arrays.asList(new String[] {"a=a", "b=b"});

            headers.put("Cookie", cookies);

             

            String greeting = greeter.greetMe("Bonjour");

             

            //After this invocation i am creating a brand new instance of binding provider .

             

            Greeter greeter1 = service1.getGreeterPort();

             

            BindingProvider bp1 = (BindingProvider)greeter1;

                               bp.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

             

             

            Map<String, List<String>> headers= CastUtils.cast((Map)bp1.getRequestContext().get("javax.xml.ws.http.request.headers"));

             

            if (headers == null) {

                headers = new HashMap<String, List<String>>();

                bp.getRequestContext().put("javax.xml.ws.http.request.headers", headers);

            }

             

            List<String> cookies = Arrays.asList(new String[] {"a=a", "b=b"});

            headers.put("Cookie", cookies);

             

            String greeting = greeter1.greetMe("Bonjour");

             

            -------------------------------------------------------------------------------------------------

            The headers set in the first BindingProvider may not be same as the headers in the second binding provider because CXF would create a different cookie for the second BindingProvider instance.

             

            So is the solution to keep the header, cookie information in a local data structure in the client side and keep copying it back to all new BindingProvider instances created from client side so that the same cookie information is relayed back to the server?

             

            But this way it would not be too different from the HttpConduit approach i had mentioned earlier.

             

            Are there any changes on the server that also needs to be done?

             

            Regards,

            Anand

            • 3. Re: How to share session between web service calls?
              Anand Jayaraman Newbie

              Hi,

               

              I needed one clarification, will this work if there are two separate instances of BindingProvider being used from client code. For e.g.

               

              Greeter greeter = service.getGreeterPort();

               

              BindingProvider bp = (BindingProvider)greeter;

                                 bp.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

               

               

              Map<String, List<String>> headers= CastUtils.cast((Map)bp.getRequestContext().get("javax.xml.ws.http.request.headers"));

               

              if (headers == null) {

                  headers = new HashMap<String, List<String>>();

                  bp.getRequestContext().put("javax.xml.ws.http.request.headers", headers);

              }

               

              List<String> cookies = Arrays.asList(new String[] {"a=a", "b=b"});

              headers.put("Cookie", cookies);

               

              String greeting = greeter.greetMe("Bonjour");

               

              //After this invocation i am creating a brand new instance of binding provider .

               

              Greeter greeter1 = service1.getGreeterPort();

               

              BindingProvider bp1 = (BindingProvider)greeter1;

                                 bp.getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY, true);

               

               

              Map<String, List<String>> headers= CastUtils.cast((Map)bp1.getRequestContext().get("javax.xml.ws.http.request.headers"));

               

              if (headers == null) {

                  headers = new HashMap<String, List<String>>();

                  bp.getRequestContext().put("javax.xml.ws.http.request.headers", headers);

              }

               

              List<String> cookies = Arrays.asList(new String[] {"a=a", "b=b"});

              headers.put("Cookie", cookies);

               

              String greeting = greeter1.greetMe("Bonjour");

               

              -------------------------------------------------------------------------------------------------

              The headers set in the first BindingProvider may not be same as the headers in the second binding provider because CXF would create a different cookie for the second BindingProvider instance.

               

              So is the solution to keep the header, cookie information in a local data structure in the client side and keep copying it back to all new BindingProvider instances created from client side so that the same cookie information is relayed back to the server?

               

              But this way it would not be too different from the HttpConduit approach i had mentioned earlier.

               

              Are there any changes on the server that also needs to be done?

               

              Regards,

              Anand

              • 4. Re: How to share session between web service calls?
                Jim Ma Apprentice
                The headers set in the first BindingProvider may not be same as the  headers in the second binding provider because CXF would create a  different cookie for the second BindingProvider instance.

                Yes. The second headers will be different from the first one .  You need to get the headers form RequestContext again .

                 

                So  is the solution to keep the header, cookie information in a local data  structure in the client side and keep copying it back to all new  BindingProvider instances created from client side so that the same  cookie information is relayed back to the server?

                Please note this is just a sample and test code from CXF code base. It just demonstrate how

                can you use the BindingProvider stuff to do this job .

                 

                But this way it would not be too different from the HttpConduit approach i had mentioned earlier.

                Well , technically speaking they are same. You have to locally maintain the cookie.  But the big different is this uses jaxws standard api . Your code is portable and can run on jbossws native or  other soap stack .  And I also do not think simply change the configuraiton can do this job .

                Are there any changes on the server that also needs to be done?

                Your current server code can work with this approach.

                • 5. Re: How to share session between web service calls?
                  Anand Jayaraman Newbie

                  Hi,

                   


                  I tried the above approach. It didn't work for me. I can clearly see two different JSESSIONIDs between the request/response. However when i use the HttpConduit approach the JSESSIONIDs are exactly the same between the two request/responses.I am pasting the code i am trying out below:

                   

                   

                   

                  String target =

                   

                  "http://localhost:9090/CXFDemo";

                   


                  IHelloService service =

                   

                  new IHelloService();

                   

                  IHello stub = service.getIHelloPort();

                   

                  BindingProvider bp = (BindingProvider)stub;

                   

                  bp.getRequestContext().put(BindingProvider.

                   

                  ENDPOINT_ADDRESS_PROPERTY, target);

                   

                  bp.getRequestContext().put(BindingProvider.

                   

                  SESSION_MAINTAIN_PROPERTY, true);

                   


                  Map<String, List<String>> headers= CastUtils.cast((Map)bp.getRequestContext().get(

                   

                  "javax.xml.ws.http.request.headers"));

                   

                  // This turns out to be null.

                   


                  if (headers == null) {

                   

                  headers =

                   

                  new HashMap<String, List<String>>();

                   

                  bp.getRequestContext().put(

                   

                  "javax.xml.ws.http.request.headers", headers);

                   

                  }

                   

                  List<String> cookies = Arrays.asList(

                   

                  new String[] {"a=a","b=b"});

                   

                  headers.put(

                   

                  "Cookie", cookies);

                   

                  String str = stub.hello(

                   

                  "hello world!!");

                   

                   

                   

                  //Creating a second service instance

                   

                  IHelloService service1 =

                   

                  new IHelloService();

                   

                  IHello stub1 = service1.getIHelloPort();

                   

                  BindingProvider provider1 = (BindingProvider)stub1;

                   

                  provider1.getRequestContext().put(BindingProvider.

                   

                  ENDPOINT_ADDRESS_PROPERTY, target);

                   

                  provider1.getRequestContext().put(BindingProvider.

                   

                  SESSION_MAINTAIN_PROPERTY, true);

                   


                  Map<String, List<String>> headers1= CastUtils.cast((Map)provider1.getRequestContext().get(

                   

                  "javax.xml.ws.http.request.headers"));

                   

                   

                   

                  if (headers1 == null) {

                   

                  headers1 =

                   

                  new HashMap<String, List<String>>();

                   


                  // Putting back the headers from the first request.

                   

                  provider1.getRequestContext().put(

                   

                  "javax.xml.ws.http.request.headers", headers);

                   

                  }

                   

                  String greeting = stub1.hello(

                   

                  "Bonjour");

                   

                   

                   

                  Please let me know if i need to correct something?

                   

                   

                  Regards,

                   

                  Anand