Tuesday, November 12, 2013

WSDL 2 Java

WSDL 2 Java
So you decided to do wsdl 2 java design. This is currently the more “proper” way to go about it. For more information about this debate see: http://docs.spring.io/spring-ws/site/reference/html/tutorial.html. You have the wsdl but how do you generate the code?

Maven Plugin

If all you need is to convert one wsdl, you can do a quite simple solution with maven using the ant plugin:

<plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-antrun-plugin</artifactId>
       <executions>
              <execution>
                     <phase>process-classes</phase>
                     <configuration>
                           <target>
                                         <java classname="org.apache.cxf.tools.wsdlto.WSDLToJava" fork="true">
                                         <arg value="-impl" />
                                         <arg value="-b" />
                                         <arg value="bindings.xjb" />
                                         <arg value="-server" />
                                         <arg value="-d" />
                                         <arg value="gen" />
                                         <arg value="-wsdlLocation" />
                                         <arg value="/WEB-INF/wsdls/my.wsdl" />
                                         <arg value="my.wsdl" />
                                         <classpath>
                                                <path refid="maven.compile.classpath" />
                                         </classpath>
                                  </java>
                           </target>
                     </configuration>
                     <goals>
                           <goal>run</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

This plugin will generate using the cxf engine a java file with all the schema files needed for the code.
This is a good solution if you just need one file or want to just look things over.
If you have multiple wsdl’s and you want to intervene during the generating process you need to do it by code. Also in the case that you do not know in advance what the wsdls are but only know the directory of the wsdls, then you need to generate them via code.

Java Code

To run the cxf engine via the java code you will need to run the same command line as above just via java code.
So why do we want to use java code and not just a simple maven plugin. First reason is, if you want to add a binding file. For more about binding please see: http://www.oracle.com/technetwork/articles/entarch/jax-ws-jaxb-customization-082750.html, https://blogs.oracle.com/sdimilla/entry/implementing_handlers_using_jaxws_2.
Binding files allows you to change the way the java code is generated. You can add annotations, or define the package name and many more things.
Binding files, recommend that you add the wsdl location in the binding file, like:
<jaxws:bindings     
  wsdlLocation="xxx.wsdl"
The disadvantage of this, is that you need to create a template binding file so that you can change the name for each wsdl file. The other option is to just omit this section in the binding file.

The main options are:  where to generate the code, whether or not to compile it, and the wsdl location. For all options see http://cxf.apache.org/docs/wsdl-to-java.html.
Another issue that needs to be handled is the location of the command path relevant to the bind file. You can put the bind file where ever you want, but when passing the location to the api, the relative path must be relative to the working directory of the command execution.  For an easy way of calculating relative paths between directories please see:

Code generation intervene

One of the features that are greatly missing is the ability to intervene in the code generation of the wsdl service file. If you want to intervene in the generation of the xsd files, you can do this with jaxb plugins.

For a nice example that adds support for XmlElementWrapper see (https://github.com/dmak/jaxb-xew-plugin). For more information on plugins and jaxb extensions see http://www.jroller.com/gmazza/entry/enhancing_jaxb_artifacts.
The problem is that for the wsdl generation cxf did not use the jaxb plugins scheme and there is no official way to intervene in the code generation.
I “hack” can be done. Cxf uses a velocity template to generate the file. The velocity template name is iml.vm. So if you write your own template (and place it in the same package as cxf template), and add it to a jar that is in the classpath before the cxf jar, your template will be used by cxf and not the internal one.

Other issues for code generation

If you are generating all the web service stubs, you will most probably also want your code to add to your cxf xml file all the proper endpoints as well.

Generation of Code

Since we will be generating the service classes from the wsdl’s you need to think if this process is a onetime process or an ongoing one. If it is part of your build system, then you cannot edit the generated files (by default cxf generates the files with a TEMP suffix). There are a few options to solve this issue. First you need to make sure that all generated files are not in the source area but in the generated (/target/ generated-sources).

You now have a few options of how to add your specific code, while still continue to regenerate the service classes. The simple one is to just copy the service class into you source code. This sort of defeats the idea of having new services added dynamically. Second solution is if you edited the  template generation you can have all services delegate the call to a central spring bean, and then use the proxy pattern to handle all calls. Third option is to add an AOP layer to catch all calls to the service and write a generic code for all of them without having to do any wiring or changing of cxf templates.