Using XML catalogs for your JAX-WS generated code

The latest JAX-WS standards make the implementation of a webservice a breeze. lately i needed to implement a client from which a WSDL is available. That proces is simple, but the client has issues when starting, the WSDL defined in the generated code is not available. In this post i describe a (the) solution to overcome this.

By means of the maven jax-ws plugin it is simple to generate all the required code for the client implementation. Just add the following to your pom file and you are done.

<plugin>
 <groupId>org.jvnet.jax-ws-commons</groupId>
 <artifactId>jaxws-maven-plugin</artifactId>
 <version>2.3</version>
 <executions>
  <execution>
   <goals>
    <goal>wsimport</goal>
   </goals>
   <!-- 
    Following configuration will invoke wsimport
    once for each wsdl. 
   -->
   <configuration>
    <wsdlLocation>
     http://example.com/mywebservices/*
    </wsdlLocation>
    <wsdlDirectory>src/mywsdls</wsdlDirectory>
    <wsdlFiles>
     <wsdlFile>a.wsdl</wsdlFile>                         
      <!-- 
       produces wsdlLocation = 
       http://example.com/mywebservices/a.wsdl 
      -->
    </wsdlFiles>
   </configuration>
  </execution>
 </executions>
</plugin>

the resulting source for the initialization will look like this:

public final static URL WSDL_LOCATION;
static {
 URL url = null;
 try {
  url = new 
   URL("http://example.com/mywebservices/a.wsdl");
 } catch (MalformedURLException e) {
 
 java.util.logging.Logger.getLogger(
  WebServiceTestClient.class.getName())
   .log(java.util.logging.Level.INFO,
     "Can not initialize the default wsdl from {0}", 
     "http://example.com/mywebservices/a.wsdl");
 }
 WSDL_LOCATION = url;
}

This all looks good when the WSDL is present at URI defined. The location specified in the location is loaded when the client is used for the first time. Not so bad right, wel yes it is. I do not want to depend on the availablity of the WSDL at the location. It might even be that it is not available. But when its not available my client will fail to start.

The solution to this problem is a XML Catalog. The previous link is a latest documentation for it, but i find that the description provided in a old version explains it a lot better.

After reading this the following XML makes sense:

<catalog 
 xmlns=
  "urn\:oasis\:names\:tc\:entity\:xmlns\:xml\:catalog"
 prefer="system">
<system 
 systemId=
  "http://localhost/wsdl/a.wsdl" 
  uri="/wsdl/a.wsdl"/>
</catalog>

The xml must be placed in a file called jax-ws-catalog.xml. Place this file in the META-INF when the generated client is in jar file and in WEB-INF if its a war.

JAX-WS uses the catalog file to resolve the URL to the specified uri. Naturally you need to include the WSDL file in your jar/war file so that is is on the classpath.

With this your client will initialize correctly when loaded by the container and no external (outside jar) files are used anymore.