SOAP web services are not cutting edge technology by any means – although it still has it’s place, REST based web services are offering tough competition. Anyway – this is definitely not a REST vs SOAP post !
I have observed a few instances where Java based SOAP web services have been used in an less than ideal manner to say the least. I think this stems from a lack of understanding around some of the basics of JAX-WS (Java EE specification for SOAP based Web Services) in general.
What’s mentioned in this post is pretty basic stuff related to SOAP based web services built using JAX-WS. Some of the points discussed are
- what’s the life cycle of a @WebService annotated POJO ?
- is it thread safe? what happens if concurrent client requests are fired at your web service ?
The @WebService annotation
Technically speaking, the @WebService annotation is all you need to turn a POJO into a SOAP endpoint. Not surprisingly enough, that’s all we generally do – annotate our class with @WebService and some other helper annotations like @WebMethod, @WebParam etc, deploy the WAR, fire up SoapUI, run a few tests and bask in glory !
Things you should know about POJOs annotated with @WebService
- A POJO annotated with @WebService deployed in a WAR is served by the Web Container (this is significant)
- Life cycle – a single instance of the POJO serves requests from the client. Pretty much like Servlets.
- Concurrency aspect (thread safety) – they are not thread safe. The same instance of the bean can be concurrently accessed by multiple threads. Although this is not a problem if your service is stateless i.e. does not use instance variables to store state – you might still face scalability issues though (after all, its just one instance !). If your POJO uses instance variables to store state, then you are in big soup and will definitely face issues w.r.t inconsistent behavior resulting from concurrent threads accessing a single instance of your web service class.
Ideally speaking . . .
- one should make the web services stateless – fire and forget style. Don’t end up storing state inside instance variables
- if you do choose to use instance variables – make sure that you as a developer, code your web service in a thread safe manner. There are multiple options here, some of which include using the good old synchronized (far from ideal though!), thread safe collections (ConcurrentHashMap) etc
- best solution IMO – if you are using a Java EE compliant application server (e.g. Weblogic), you should invariably deploy your web services as an EJB (I am not going to dive into the details of EJBs here ! You can refer to my previous posts if interested).
- What will you gain by that ? (1) EJBs are thread safe by default. You need not worry about coding concurrency and thread safety as a part of your business logic – you get that for free ! (2) EJBs are pooled components – The container caches instances in memory and allocates them to clients as per request. Scalability for free (note – EJB pooling configurations are container specific and each server defines a specific manner in which to achieve this) (3) EJBs are transnational by default – in case you are accessing back end databases as a part of your web service logic, EJBs are ideal (details of transactions are best dealt by a guy who really understands them in depth! I am not going to embarrass myself by trying to act as if I know them end to end)
- How do I ‘pump-up’ my web service ? (1) Just use the @Stateless annotation – this turns your mere POJO into a full fledged EJB which can now enjoy all the container services (2) deploy your web service not as a WAR, but as an EJB-JAR packed within an EAR. This will ensure that the EJB container catches hold of your POJO and weaves all the magic I have been bragging about!
I am not a testing expert – but tools like JMeter can make me look smart! Do yourself a favor and user JMeter to ease your SOAP web service testing process. It’s not that hard. Trivial example below
- As far as generating stubs from an existing WSDL is concerned, I would definitely opt for the standard capability within Java SE itself. I am simply stating this because this has worked flawlessly for me in the past instead of trying out other implementations like Axis 2 or Apache CXF
- I don’t mean to undermine them but I don’t see the value in wasting time looking into other stuff when the JDK itself has a well documented standard tool ! Just hop over to JAVA_HOME/bin, look for the wsimport command and get cracking.
- Most of the IDEs which provide stub generation capability leverage this very tool
This was just a quick rant of sorts..! Hope it made sense