Wednesday, February 26, 2014

Deploying older JAX-WS applications on WAS 7 or higher (Web Service not recognized)


At my company, we've recently been making a large move from Websphere Application Server(WAS) V6.1 to v8.0.  Some of our web service applications have noticed that if they were exposing JAX-WS service in their app and they simply deployed their app to WAS v8.0, their JAX-WS service was not recognized.  That is there are no errors, but the service is not exposed in anyway.  You can't reach it.

This turns out to be due to the way WAS does the scanning for the JAX-WS annotations.  This article from IBM helps explain it, but I'll give my abbreviated version as well...

Turns out that on WAS 6.1 with the WS Feature pack, WAS would scan your web app for JAX-WS annotations and if a Web Service was found it would expose it properly.  However, as of WAS 7, only Java EE 5 compliant modules are scanned.  That means if you created your app for WAS 6.1, then your web project would have been Java EE 1.4 compatible.  Check out wikipedia for a nice chart of WAS versions and their version support.

Java EE 1.4 means your web module will be version 2.4 where in Java EE 5, your web module would be 2.5.  So, if your web module (war) is not 2.5, then WAS 7 and beyond will not scan it for JAX-WS annotations and therefore your JAX-WS web services will never be exposed.

There are two fixes for this.

1) Upgrade your web module to 2.5 to be Java EE 5 compliant and then WAS 7 and higher will scan it for JAX-WS services.

2) Add a special IBM specific flag in your web applciations META-INF/MANIFEST.MF file like this:
Manifest-Version: 1.0
UseWSFEP61ScanPolicy: true

In the second option, this tell WAS to scan for the JAX-WS annotations even though its an older web module.


If you are using maven you may need to modify your POM file if maven is creating your MANIFEST.MF files.  This stackoverflow post helped us.

Here's what we ended up with:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<warSourceDirectory>webapp</warSourceDirectory>
<webXml>webapp/WEB-INF/web.xml</webXml>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
        <UseWSFEP61ScanPolicy>true</UseWSFEP61ScanPolicy>
      </manifestEntries>
</archive>
</configuration>
</plugin>
...



With this configuration we were able to have maven build our META-INF/MANIFEST.MF file in the war and add the special flag "UseWSFEP61ScanPolicy"

Hope this helps.



Building JAX-WS application with Maven


I was having issues building a JAX-WS application using Maven(NOTE: I'm using maven 2.0.11), when I generated my JAX-WS code using JAX-WS 2.2.  I saw errors like this:

cannot find symbol
symbol  : method required()
location: @interface javax.xml.bind.annotation.XmlElementRef

or

cannot find symbol
symbol  : constructor Service(java.net.URL,javax.xml.namespace.QName,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service

This blog really helped me find my solution.

I'll summarize briefly what the issue was.

Java comes with several specifications APIs packaged into it, like JAX-WS & JAXB. However, the version of these specifications are not always the latest.   That is, newer versions of JAX-WS and JAXB may be released, but are not in the version of Java you may be using to compile with.  Even if the newer version is available on your server runtime, they may not be available in your JDK.  And even if you try to explicitly try to add the newer versions of the JAX-WS and JAXB jars to your maven dependency section, it still will not work.

In order to override the built in versions of the JAX-WS and JAXB, you have to utilize the "endorsed" folder.   Follow this link to learn more about the "endorsed" folder.

In short, adding newer versions of the jars to an endorsed folder in your JDK allow them to override any embedded versions.

So, the big question then is how to do this with maven.  Here's the answer..

You use the maven-dependency-plugin to create the "endorsed" folder and copy the newer version of the jars into it.  Then you update the maven-compiler-plugin to refer to this endorsed folder.

Here's a sample POM.


<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<endorseddirs>${project.build.directory}/endorsed</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/endorsed</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2</version>
<type>jar</type>
</artifactItem>
<artifactItem>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.2</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>


With these settings we were able to successfully build our JAX-WS 2.2 code with Maven.

Hope this helps!