views:

340

answers:

3

Hi

I'd like to know the correct / best way to handle concurrency with an Axis2 webservice.

Eg, given this code:

public class MyServiceDelegate
{
    @Resource
    UserWebService service; // Injected by spring

    public CustomerDTO getCustomer()
    {
       String sessionString = getSessionStringFromCookies();
       service.setJSESSIONID(sessionString);
       CustomerDTO customer = service.getCustomerFromSessionID();
    }
}

Note that in the above that UserWebService is a 3rd party API. The service requires that when making calls, we pass a cookie with the JSESSIONID of an authenticated session.

Am I correct in assuming that this statement is not threadsafe? IE., given two threads, is it possible for the following to occur?

  • ThreadA : service.setJSESSIONID("threadA")
  • ThreadB : service.setJSESSIONID("threadB")
  • ThreadA : service.getCustomerFromSessionID // service.sesionID == "threadB"

If so, what's the most appropriate way to handle this situation? Should I use a resource pool for service? Or should I declare service as synchronized?

    public CustomerDTO getCustomer()
    {
       synchronized( service ) {
          service.setJSESSIONID(sessionString);
          CustomerDTO customer = service.getCustomerFromSessionID();
       }
    }

Or, is there another, more appropriate way to handle this problem?

Regards

Marty

+2  A: 

Would each thread have its own Delegate object and hence its own UserWebService service?

In the simple case, if delegates are created on the stack the threads would be independent.

If the cost of creation is high, have a pool of the delegate objects. Taking one from teh pool is comparativley cheap. You need to be very careful with housekeeping, but effectively this is what is done with database connections. Some environments have utility classes for managing such pooling - tends to be preferable to rolling your own.

djna
Marty Pitt
edited to add alternative design
djna
A: 

Is UserWebService one of your classes? If so, I think I'd change the method signature to:

public CustomerDTO getCustomer()
{
      CustomerDTO customer = service.getCustomerFromSessionID(sessionString);
}

And not have your UserWebService maintain state, that way it will be inherently thread-safe

MrWiggles
Unfortunately, no. And the service requires that prior to making a call to it, we set the JSESSION ID on the service so that it may identify the authenticated session we're using.
Marty Pitt
I'm infering that the session id is something set on the delegate object, and then one invokes the remote service, with the session id being conceptually in a cookie. In which case wrapping up calls still leave the possibilitiy of a race.
djna
A: 

As you said, the function is not thread safe. Java has a simple way to make monitors, which is an object that only allows one thread to access a function at a time. More info on monitors

To make it thread safe you can put synchronized either, as you did, around the expression, or before the function name:

public synchronized CustomerDTO getCustomer(){
    service.setJSESSIONID(sessionString);
    CustomerDTO customer = service.getCustomerFromSessionID();
}

The difference between the two is which object you turn into a monitor.

Marius
In this scenario, is there a reason to prefer a synchronized method over a delegate pool (or vice versa?)
Marty Pitt
synchronizing for the duration of a web service call sounds like a really bad idea to me. Delegate Pool is teh way I would go.
djna