Inconsistency of JAX-WS Service Implementation Bean

Apr 17, 2011 by

Bottom line : Different JAX-WS runtime may take different approach in managing the life cycle of JAX-WS service implementation bean. JAX-WS RI takes a Servlet-like approach but WebSphere choose the different one.

Many years ago, my team leader at the time asked me what library we should pick for parsing our XML data. He said what he had in his mind were Xerces, Xalan and JAXP and he personally thought that JAXP is the fastest. I don’t recall my answer but I remember that I didn’t correct him at the time. The thing is that JAXP is just a specification but Xerces and Xalan are implementation so the two categories can’t be compared.

The world of Java is like this; full of specifications. A specification will be implemented by vendors. The ideal concept is that you can write your program based on a standard specification and the program will be able to run on any implementations and on any platforms. Well, we all know that it is far from perfect. Sometimes, a specification is not so clear or it is full of details but only the supernatural-brain developers can understand it. There are always grey areas that various implementations behave differently and it’s up to debate whether the behaviors are allowed by the spec.

Let’s look at the thing related to this specification headache that I want to talk about.

@WebService
public class NewsProvider {
    public NewsProvider(){ log("NewsProvider instance created");  }

    @PostConstruct
    public void init(){ log("NewsProvider-@PostConstruct called"); }

    @PreDestroy
    public void destroy(){ log("NewsProvider-@PreDestroy called"); }

    @WebMethod
    public String getProviderName() throws InterruptedException{
        log("getProviderName()");
        return "Devguli.com";
    }

    private void log(String msg){
        System.out.println(msg + " : hashCode=" + hashCode()
                + ", Thread=" + Thread.currentThread().getName());
    }
}

The above primitive code-first service implementation bean is a kind of code that may be found on typical JAX-WS tutorials. I think every Java web developers are well familiar with this pattern of managed component life cycle. In the old days, there may be an interface for us to implement but these days we can just use annotations to mark the hook for initializing our component, the method that implement the business logic and the hook for cleanup logic. It is just like the pattern of using init(), service() and destroy() methods of Servlet. When I start learning JAX-WS, I didn’t even bother to find more information about those annotations. I thought just a short example code was enough for me to guess how it worked. If you run the above code on JAX-WS RI then it looks just like Servlet.

Apr 16, 2011 5:05:49 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized INFO: WSSERVLET12: JAX-WS context listener initializing
NewsProvider instance created : hashCode=16904839, Thread=http-8084-1
NewsProvider-@PostConstruct called : hashCode=16904839, Thread=http-8084-1
getProviderName() : hashCode=16904839, Thread=http-8084-2
getProviderName() : hashCode=16904839, Thread=http-8084-4
getProviderName() : hashCode=16904839, Thread=http-8084-1
getProviderName() : hashCode=16904839, Thread=http-8084-5
getProviderName() : hashCode=16904839, Thread=http-8084-3
getProviderName() : hashCode=16904839, Thread=http-8084-3
getProviderName() : hashCode=16904839, Thread=http-8084-5
getProviderName() : hashCode=16904839, Thread=http-8084-4
getProviderName() : hashCode=16904839, Thread=http-8084-1
NewsProvider-@PreDestroy called : hashCode=16904839, Thread=http-8084-1
Apr 16, 2011 5:16:06 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate destroy
INFO: WSSERVLET15: JAX-WS servlet destroyed
Apr 16, 2011 5:16:06 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextDestroyed
INFO: WSSERVLET13: JAX-WS context listener destroyed

JAX-WS runtime will create only one instance of Newsprovider and share it between all request threads. The @PostConstruct method of the instance will be called before it is considered ready to serve its client via getProviderName() method. The @PreDestroy method will be called before the hosting web application is stopped or undeployed.

Note: The above output is the result of running NewsProvider as a Servlet-based web services on Tomcat. When I first experienced this problem, I was developing my project using Netbeans and GlassfishV2. We learned of the problem in our system test which was executed on WebSphere.

If this is the same programming model as of Servlet then it is quite natural for us to initialize expensive resource in @ PostConstruct method. I did just like that and got strange errors or performance drop when I ran my project on WebSphere. The output below show how our NewsProvider behave on WebSphere.

SystemOut O NewsProvider instance created : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O NewsProvider-@PostConstruct called : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O getProviderName() : hashCode=1715234364, Thread=WebContainer : 0
SystemOut O NewsProvider instance created : hashCode=707537452, Thread=WebContainer : 1
SystemOut O NewsProvider-@PostConstruct called : hashCode=707537452, Thread=WebContainer : 1
SystemOut O getProviderName() : hashCode=707537452, Thread=WebContainer : 1
SystemOut O NewsProvider instance created : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O NewsProvider-@PostConstruct called : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O getProviderName() : hashCode=1346654276, Thread=WebContainer : 2
SystemOut O NewsProvider instance created : hashCode=475012176, Thread=WebContainer : 3
SystemOut O NewsProvider-@PostConstruct called : hashCode=475012176, Thread=WebContainer : 3
SystemOut O getProviderName() : hashCode=475012176, Thread=WebContainer : 3

WebSphere will create a new instance of service implementation bean for each request. You can see that this will definitely cause a big problem if we perform initializing of some expensive resources there in @ PostConstruct method.

Another thing that I haven’t been able to figure it out yet is that the @PreDestroy hasn’t been called at all even when the web application has been stopped and undeployed. I personally don’t think that WebSphere treats @PreDestroy as optional. It’s too strange that the initializing method has been called but the cleanup has been ignored. I will blog about this if I can find more information about it.

Specification

Servlet specification has stated clearly in SRV.2.2 Number of Instances :

For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration

Both JAX-WS and JSR109 specifications don’t seem to directly state the rule of number of instance but in the 5.3.2.4.2 Web container programming model for JAX-WS ( JSR 109), there is a bullet says:

A Service Implementation must be a stateless object. A Service Implementation Bean must not save client specific state across method calls either within the bean instance’s data members or external to the instance. A container may use any bean instance to service a request

From looking at several sections of the spec, I got a feeling that JAX-WS containers are allowed to create multiple instance of service implementation bean. I couldn’t find any place in the spec suggesting that @PreDestroy can be ignored though.

Addressing the inconsistency

To address this problem, I personally prefer initialing and cleanup all components in ServletContextListener since the behavior of it is quite consistent in all Servlet container. I will make service implementation bean a light weight and stateless class so JAX-WS runtime may choose to created many instance of it. The Bean will just pass web services parameter to the real business logic implementation.

read more

Related Posts

Share This

I don’t know what exactly web services are

May 11, 2010 by

Back in my days at university, if anybody asked me or my friends “what is the difference between web application and web services” then the answers would be exactly the same; “web application is human-to-machine interaction but web services are machine-to-machine interaction”. I don’t recall how I and my friends got to remember the answers but we all had the perception that it was the most preferable answer. At the time, web services were very new. Tools and concept related to the topic were not matured yet especially for Java world which was quite late for the web services train. My self-study involved a lot of reading, trying to guess what exactly web services were. The perception of web services in my mind was that it was something very advanced involving many technologies working together to overcome all those problems that had been troubling distributed computing for a long time.

My professor once gave an assignment to the class to think of use-cases that could be implemented as web services. I recalled having an argument with one of my friend about this assignment. He suggested that a simple thing like providing basic information to client could be implemented as web services. I didn’t recall what exactly he suggested but it was so simple and contrasted strongly with my perception of web services at the time. We had discussion and I kept telling him his idea was not web service. He finally asked me “what are web services then” and I didn’t know what to answer.

One characteristic associated with web services at its early state was the capability of performing dynamic integration with other systems. A service provider could look up for a potential collaborator from UDDI server and performed some kind of binding to integrate the functionality of the collaborator into the service provider. A book portal web services might look up for book store web services at runtime to find the cheapest price for a particular book order. This just-in-time integration was the reason that I hesitated to accept that the idea of my friend could be called web services. I felt like the idea was just a simple request/reply scenario. It didn’t feature the great web services vision at all.

Years have passed. The technologies around web services have become more matured.
I am now less interested in finding the definition of web services and more interested in learning what each web services technology actually does. I am well familiar with WSDL, SOAP, JAX-WS JAXB and the other java web services specifications. Having something that I can actually play with gives me more confident feeling on what web services are about. I still don’t have one universal definition for web services and don’t think I will ever able to come up with one. But I can tell you with confidence what a particular web services technology does and what it doesn’t do.

Looking back when I started learning web services, I wonder if the vision of just-in-time integration has ever been realized at all. How is it possible for two parties with no common understanding to dynamically integrate with each other to form business services? Let’s say I am writing a book portal program. The program dynamically looks up for a collaborator and gets back BarnesAndNoble.wsdl. How can the program automatically know what operation defined in the WSDL file should be called to get current price of a book? If the operation accept request message as an xml element with type string, should the program fill in the name of the book or the ISBN? It seems like this kind of integration is impossible without a shared understanding or predefined protocol between two parties. It is strange that these questions had never entered my head when I was still in my university at all. I just thought that this thing could be done. I just needed to learn more to know how it worked.

I have recently come across an interesting article; Web Services: It’s So Crazy, It Just Might Not Work. The author has stated a very interesting point saying that “Parseable != Interoperable”. The fact that web services use XML as data format doesn’t automatically make all web services interoperable. XML may be an open standard which can be parsed in any platform but web services are not only required to be able to parse XML messages, it also need to understand the meaning of the messages as well.

“At best, XML makes it possible for businesses or developer groups to share data, provided they agree on the semantics of that data in advance. This is not to say XML is not an enormous advance. It plainly is. However, its advance lies in aiding data interoperability where shared semantics can be assumed. It does nothing at all to create semantic interoperability.”

What I believe web services are about
I may not know what exactly web services are but I can tell you what I believe web services are about

System Integration: We expose our system as web services because we want other systems on whatever platform to integrate with our system with less pain. The ultimate goal is easy integration and not anything else so you should keep you product manager from going out to claim this new technology is going to make your product run faster.

Machine-to-machine interaction: what is the reason of using web services to implement a simple use-case like searching books based on certain simple criteria, given the fact that the use-case can be done by a normal web application.

You may implement the book searching system as a web application which users can access via web browser. A user may see a text field with “Criteria” label in front of it, he type it some criteria and click submit button to get search result. This communication is between human and your web application. But if you choose to expose your application as a web services then you expect users to write a piece of code to connect to your system and call the search service programmatically. A user may be building a book price comparing system which connects to various book providers.

A lot of XML: If you are good at web services development then you are definitely good at XML programming.

read more

Related Posts

Share This

Java Web Services Deployment Model

Apr 13, 2010 by

The product I am developing is going to come out in early access package pretty soon. My QA and Support team are still not quite get it why the web services in our product needs additional steps to add some descriptor files when it going to be deployed on Sun Java System Web Server. I also found this confusion quite commonplace among beginners who start learning JAX-WS. I would like to explain it here so the next time somebody asks me again then I can just direct him to this post.

Java EE deployment model
The final package of JAX-WS web services is an ordinary war file just like any other Servlet/JSP web application’s war file. If you look at the basic JAX-WS tutorial you will notice that the implementation can be as minimal as a simple Java class with a couple of web service annotations.

@WebService()
public class NewsService {
    public String[] getAlert(){
        //implementation
    }
}

You can just pack this class to a war file without the need of any descriptor file even web.xml and then deploy it to Java EE application server to get a nice and simple web services.

You are able to do this kind of deployment because your application server has implemented all the necessary specifications for developing/deploying web services on Java EE platform. The main specification defining potable programming model for Java EE platform is JSR-109 (Implementing Enterprise Web Services). If you search internet and mailing list, you may found many developers call web services with this kind of deployment model as “JSR-109 web services”. Actually, JSR-109 always works together with other specification like JSR-224 (JAX-WS) and JSR-181 (web services annotation) so I will choose to call this deployment model “Java EE deployment model”.

If you choose to make your web services compliant with JSR-109 specification then your war file can be deployed on any Java EE application servers that support the specification. I have developed my unit testing on Glassfish and give the same package to QA team to run system test on WebSphere.

Now, let’s look at it in the real action.
Here we are creating a web services stating from creating a web application project. To demonstrate JSR109 web services, I will choose target server to be Glassfish which is a full Java EE application server.

ChoosingContainer

Once you have created a web service (using web services wizard or manually create java class with web services annotation), you will see that there is nothing in your web.xnl that related to web services information. You can ignore the sun-web.xml, this file is specific to Glassfish and it is not descriptor in our main topic. You may want to delete all descriptor in WEB-INF and deploy your web application to see that your web services application is still able to work properly.

JSR109_IDE

Here is the default web.xml file content.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Now you may want to look at the final war file that you can distribute to your client.
You will see that there is no web services library packed in your war file at all. Since this is JSR109 web services so it expect Java EE server to provide all necessary libraries.

D:\Program\netbeans-projects\JSR109\dist>jar -tf JSR109.war
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/ws/
WEB-INF/classes/ws/news/
WEB-INF/classes/ws/news/NewsService.class
index.jsp

Servlet Based deployment model
If you want to deploy the NewsService example above on non full Java EE server (Sun Java System Web Server, Tomcat) then you may have some concerns to think about.

The most important concern is that this kind of deployment is not portable. From the eyes of the non Java EE container, your web services war file is no different from the normal Servlt/JSP web application’s war file. If you want to do web services then you have to choose an implementation of JAX-WS and pack all the necessary libraries into your war. Now you will get a web application that happens to have some libraries that know how to do web services.

Another thing is that your web services implementation classes are not going to be automatically discovered by your container. You will have to edit some file descriptors to tell your JAX-WS implementation library to know how you want your web services to be deployed. These descriptors are specific to the library you are using. The web services in my product need sun-jaxws.xml file when it is going to be deployed on SJSWS because we are using SUN JAX-WS reference implementation for this kind of deployment.

In NetBeans, if you choose target server to be Apache Tomcat then you will get the war file structure as shown below.

ServletBased_IDE

You will see that sun-jaxws.xml file will be added to your WEB-INF directory once you create a web services. Both sun-jaxws.xml and web.xml will contain descriptive information about your web services.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <listener>
        <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>NewsService</servlet-name>
        <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>NewsService</servlet-name>
        <url-pattern>/NewsService</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

sun-jaxws.xml

<endpoints version="2.0" xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime">
  <endpoint implementation="ws.news.NewsService" name="NewsService" url-pattern="/NewsService"/>
</endpoints>

And here is the layout of the final package.
D:\Program\netbeans-projects\ServletBasedWS\dist>jar -tf ServletBasedWS.war
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/ws/
WEB-INF/classes/ws/news/
WEB-INF/lib/
META-INF/context.xml
WEB-INF/classes/ws/news/NewsService.class
WEB-INF/lib/activation.jar
WEB-INF/lib/webservices-api.jar
WEB-INF/lib/webservices-extra-api.jar
WEB-INF/lib/webservices-extra.jar
WEB-INF/lib/webservices-rt.jar
WEB-INF/lib/webservices-tools.jar
WEB-INF/sun-jaxws.xml
WEB-INF/web.xml
index.jsp

You will see that jar files of METRO (JAX-WS RI ) have been packed along with our final war file.

read more

Related Posts

Share This