Generating a WSDL-first web service using SoapUI tool integration
This recipe shows how to configure SoapUI (Apache CXF) tool integration to generate a runnable Java web service with an empty implementation using its WSDL. This could be useful if you need a quick menu-driven way to create a SOAP web service that can be implemented and deployed separately to SoapUI.
Getting ready
The WSDL that we are going to use defines a simple invoice service. It has only one operation to retrieve a basic invoice document using its invoice number:
- Operation:
getInvoice
- Request:
invoiceNo : string
- Response:
InvoiceDocument (invoiceNo : string, company : string, amount : string)
- Location:
http://localhost:9001/ws/invoice/v1
The WSDL can be found at soap/invoicev1/wsdl/invoice_v1.wsdl
in this chapter's sample code.
We'll need the Apache CXF web service framework to generate the web service stub using SoapUI tooling. Download the latest version from http://cxf.apache.org/download.html (I have used version 3.01).
Tip
Apache CXF Version
Despite the tool menu stating version 2.x, you can go for the latest version, which, at the time of writing, is 3.01 (requires JDK 1.7+). Otherwise, choose version 2.7.x for JDK 1.6+ support, or version 2.6.x for JDK 1.5 support.
To build and run the service Java code, the minimum you will need is a suitable JDK. I have used JDK 1.7.0_25. Optionally, you may also want to use an IDE like Eclipse to make easy the work of exploring, building, and running the generated web service code.
Tip
Other SoapUI Tools
While you are free to choose any alternate framework supported by SoapUI tools (see http://www.soapui.org/SOAP-and-WSDL/code-generation.html), note that although the principles will stay the same, the command details and the resulting generated web service artifacts will of course vary.
How to do it...
First, we need to configure SoapUI to be able to generate and build the invoice web service. Then, we can run it as a standard Java executable. Perform the following steps:
- In SoapUI, go to Tools | Apache CXF, and when the Apache CXF Stubs window appears, click on the Tools button to bring up the SoapUI Preferences window. Here, browse to the location where you downloaded Apache CXF, select the
bin
directory, and then click on OK: - Next, we need to configure the generation options under the Basic tab. The main points are:
- WSDL location: For example,
<chapter1 samples>/soap/invoicev1/wsdl/invoice_v1.wsdl
. - Output directory: This is where the generated source code will end up; for example;
<chapter1 samples>/soap/invoicev1/src/main/java
. - Package Structure: This is for the generated source code; for example,
ws.invoice.v1
. - Artifact Options: Only tick Server and Implementation. However, the client and Ant build file options are also available. We will be using SoapUI as our client and won't require Ant.
- WSDL location: For example,
- To automatically compile our generated service code, under the Advanced tab, do the following:
- Tick Compile.
- Supply a Class Folder value for the resulting Java class files, for example,
<chapter1 samples>/soap/invoicev1/target/classes
. - Tick Validate WSDL (optional) under the advanced tab to check the structure and get basic WS-I compliance checks on your WSDL. Note that the
invoice_v1.wsdl
should not produce any output with this option. - Leave all other fields and checkboxes unchanged.
- Under the Custom Args tab, enter
–wsdlLocation invoice_v1.wsdl
in Tool Args. This tells the web service code where to look for the WSDL file at runtime. Setting the value like this means thatinvoice_v1.wsdl
is expected to be the root of theclasses
directory. More on this in the next section. - Now, we are ready to click on Generate! If all goes well, you should see an output similar to the following:
You should also see the following generated Java source files in your output folder, for example:
<chapter1 samples>/soap/invoicev1/src/main/java/ws/invoice/v1/ InvoiceDocumentType.java InvoicePortType_InvoicePort_Server.java ObjectFactory.java InvoicePortImpl.java InvoiceRefType.java package-info.java InvoicePortType.java InvoiceServiceV1.java
The corresponding class files in your class folder, for example:
<chapter1 samples>/soap/invoicev1/target/classes/ws/invoice/v1/
Note
Mac/Linux Issue
I suspect that there is a minor SoapUI bug here. If you get an error like
sh: ./wsdl2java.sh: No such file or directory
, then an easy fix is to open a shell in<Apache CXF Home>/bin/
and copywsdl2java
towsdl2java.sh
; for example,cp wsdl2java wsdl2java.sh
. - Before we run the server, we need to copy
invoice_v1.wsdl
into the classes folder location, for example, into<chapter1 samples>/soap/invoicev1/target/classes
. Otherwise, when the server is run, you will see an error like[failed to localize] cannot.load.wsdl(invoice_v1.wsdl)
. - Finally, we are ready to start the server:
cd <chapter1 samples>/soap/invoicev1/target/classes java ws.invoice.v1.InvoicePortType_InvoicePort_Server Starting Server Server ready...
To confirm whether it's actually working, open a browser and go to http://localhost:9001/ws/invoice/v1?wsdl
, and you should see the (invoice_v1.wsdl
) WSDL displayed. Our generated server is up and running.
How it works...
All that SoapUI is actually doing is building command-line parameters for the various web service frameworks to do the generation. In this example, those happy with the command line could just run <Apache CXF Home>/bin/wsdl2java
directly.
Note
Apache CXF wsdl2java script
For more info on the wsdl2java
options, see http://cxf.apache.org/docs/wsdl-to-java.html.
Let's take a quick look at the generated source files. The main points are as follows:
- Running the
wsdl2java
option generates Java standard JAX-WS web service code with types and methods derived from the WSDL. - The Java JDK ships with an implementation of JAX-WS:
- There's no need for any additional compile or runtime libraries, for example, Apache CXF libs.
- No servlet container is required to publish the web service, for example, Tomcat or Jetty. If you look in
InvoicePortType_InvoicePort_Server.java
, you can see that the service is published using JDK's default HTTP server provided by thejavax.xml.ws.Endpoint
class. The staticEndpoint.publish(…)
binds our generated service implementation (InvoicePortImpl.java
) to the endpoint address so that invoice requests are handled by ourgetInvoice(…)
method.
- The service is very portable; that is, only a Java JRE is needed to run it.
- The WSDL file is required at runtime. The
wsdlLocation
parameter supplied in step 4 sets an attribute of the@javax.jws.WebService
annotation in the classInvoicePortImpl.java
. - The server endpoint and timeout (the default value is 5 minutes) are easy to change. Edit
InvoicePortType_InvoicePort_Server.java
:- Endpoint:
String address = "http://localhost:9001/ws/invoice/v1";
- Timeout:
Thread.sleep(5 * 60 * 1000);
- Requires recompile
- Endpoint:
There's more...
If the generated web service stub is to be used as the basis for on-going service development, then managing the generation, build, and deploy cycle externally to SoapUI using a build framework such as Ant, Maven, or Gradle will probably be a better option. To help with this, Apache CXF has a good Maven plugin to provide similar code generation; refer to http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html.
For those who want a quick and high-level way to generate a working web service for testing purposes, I would expect SoapUI's excellent mocking features to be a more convenient option than code generation in many cases (See Chapter 3, Developing and Deploying Dynamic REST and SOAP Mocks).
The SOAP web service stub journey will be continued in the next recipe when we add simple SoapUI tests and a basic implementation to pass them.
See also
- To access the Java 1.6 JAX-WS tutorial, go to http://docs.oracle.com/javaee/6/tutorial/doc/bnayl.html