Tuesday, July 10, 2007

Q: Why won't my JDeveloper JAX-WS web service deploy to glassfish?

A: Not so standard standards

We have a few reports of customers building JAX-WS web services in JDeveloper 11 Technology Preview; but finding that they get some strange errors when trying to deploy these services to glassfish. (Also Tomcat which I haven't had time to play with; but I suspect that they both have the same root cause)

To investigate this I downloaded the latest beta of glassfish version 2 to try to work out what is going on. This prove to be really quite easy to do using the quick start guide. As detailed in the guide I dropped my simple example web service in the auto deploy directory and was rewarded with a pleasing _deployed response file.

Right I thought, lets use the web service. So I went to the management console to see if they have a tester like OC4J. Indeed they did with a handy page listing all deployed web services; but this is where things started to fall apart. Any attempt to test the service or view the WSDL would be met with a 404 response.

It turns out that if I had looked in the server.log file I would have found the following message:

Servlet /WebServices threw load() exception
java.lang.ClassCastException: org.kingsfleet.MathService cannot be cast to
       at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1007)
       at org.apache.catalina.core.StandardContext.start(StandardContext.java:5188)
       at com.sun.enterprise.web.WebModule.start(WebModule.java:324)

This relates to the servlet-class element in the web.xml that we, JDeveloper, generates when we create the service for the first time. This is a quick way to specify how the endpoint maps to a URL. Here is a simple example:

<?xml version = '1.0' encoding = 'US-ASCII'?>
<web-app 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" version="2.5" 
    <description>Empty web.xml file for Web Application</description>

Now it may not make sense to put a class that doesn't implement servlet in this place; but that is how the people who wrote JSR 109 decided it should work. I have to say that it is a nice clean and apparently platform non-specific way of working.

If you remove the servlet mappings or indeed the web.xml from the war file (Okay hands up; you can't create a war file without a web.xml in the technology preview logged as bug 6195725) then this web service will deploy, but at a slightly different URL to the one you actually wanted. To take control over the endpoint url then you will need to create sun-jaws.xml and modify web example as in this tutorial. This is less than optimal because it contains platform-specific implementation classes that might not be portable across different app servers.

I have raised a bug to track this issue but the glassfish people don't appear to be fussed about fixing this problem even though it appears to break the CTS compliance tests. They do seem to be fixing the admin console so that it won't show a web service that has failed to deploy which at least will reduce the level of confusion just a little bit.

Hopefully one day we will get WORA for web services; but it looks like we are not quite there yet.


Jin Kwon said...

Hey Gerard.

Did you find the way of portable yet standard way to work with this?

Is there any other application server that supports that standard JSR thing?

I'm writing a WS demo.
And I couldn't work it out.
And I'm here with your blog.

I hate sun's javaeetutorial.
It's worse than apaches' usage.
People even can't follow the tutorial without netbeans. Ha...


Gerard Davison said...

No I am affraid not....

Archimedes Trajano said...

Tried to do this using the standards, I couldn't get it working with Jetty. Actually I used the following https://cwiki.apache.org/GMOxDOC21/developing-a-jax-ws-pojo-web-service.html#DevelopingaJAX-WSPOJOWebService-DeploytheWebService

to try and guide me but no luck.

The closest I have gotten is CXF but with the export JAVA_OPTS=-Dorg.apache.cxf.jaxws.checkPublishEndpointPermission=false