spacer
spacer

JAX-WS

Introduction

The JAX-WS 1) standard is implemented by a number of SOAP toolkits. In most cases when we talk about JAX-WS we are referring to the JAX-WS Reference Implementation 2) rather than the standard itself.

Note: JAX-WS does not support RPC/encoded style SOAP services and so cannot be used with some EMBL-EBI web services. See the SOAP and WSDL sections of the guide for more information about SOAP styles.

Installation

JAX-WS is included as part of the Java 6 platform and thus is available if Java 6 or later is installed. If using Java 5 JAX-WS is available for download from http://jax-ws.java.net/.

EMBL-EBI Sample Client Dependencies

For the JAX-WS based sample clients we provide an archive containing additional required dependencies (e.g. Apache commons-cli 3) ): lib-1.4.zip.

This can be used via the -Djava.ext.dirs option when running a client, for example if the lib-1.4.zip archive was unpacked in the current directory (creating a lib sub-directory) and the sample WSDbfetch client jar is in the current directory the client could be run using:

java -Djava.ext.dirs=lib -jar WSDbfetch_JAXWS.jar

Creating Stubs Using wsimport

The wsimport tool is used to generates client classes representing the service interface from a WSDL interface definition. By default the generated .class files will be placed into a package based on the namespace(s) used in the WSDL. To specify a specific package for the generated classes use the -p option.

For details of the WSDL documents available for EBI Web Services see the service page for the service of interest.

Specific Apache ant 4) and Apache Maven 5) tasks for generating stubs from WSDL documents are available, see the JAX-WS documentation for details.

Command-line

To generate stubs from a WSDL, in this case for EB-eye, use the wsimport command:

wsimport -d bin -p uk.ac.ebi.webservices.ebeye -keep -s src http://www.ebi.ac.uk/ebisearch/service.ebi?wsdl

In this case the stubs are generated in the uk.ac.ebi.www.ebeye Java package (-p), the generated classes are placed in the bin/ directory (-d), the generated source code is retained (-keep) and the sources are placed in the src/ directory (-s).

Apache ant: generic task

To build stubs using the Apache ant build tool, without having to install additional tasks, a generic target can be defined which generates code stubs from a WSDL document:

<!-- Generate JAX-WS stubs from a WSDL -->
<!--
  Using the wsimport command:
  wsimport -d bin -p uk.ac.ebi.webservices.ebeye -keep -s src http://www.ebi.ac.uk/ebisearch/service.ebi?wsdl
  NB: assumes wsimport is on the current PATH.
-->
<target name="genJaxwsStubs"
  description="JAX-WS RI: generate stubs from a WSDL using wsimport command">
  <echo message="${stubPkg}" />
  <echo message="${wsdlUrl}" />
  <exec executable="wsimport">
    <arg value="-d" />
    <arg value="${build.dir}" />
    <arg value="-p" />
    <arg value="${stubPkg}" />
    <arg value="-keep" />
    <arg value="-s" />
    <arg value="${src.dir}" />
    <arg value="-Xnocompile" />
    <arg value="${wsdlUrl}" />
  </exec>
</target>

This assumes that the wsimport command is available on the PATH.

The genJaxwsStubs target can then be called with parameters in a service specific target to generate the stubs, for example for WSDbfetch:

<!-- Generate JAX-WS stubs for WSDbfetch -->
<target name="jaxws-stubs-wsdbfetch" description="JAX-WS RI: generate stubs for WSDbfetch (document/literal SOAP)">
  <antcall target="genJaxwsStubs">
    <param name="stubPkg" value="uk.ac.ebi.webservices.jaxws.stubs.wsdbfetch" />
    <param name="wsdlUrl" value="http://www.ebi.ac.uk/ws/services/WSDbfetchDoclit?wsdl" />
  </antcall>
</target>

The target can then be referenced when invoking ant to generate the stubs:

ant jaxws-stubs-wsdbfetch

An Apache ant build.xml file using this method to generate stubs for JAX-WS is included in the exercise project: java_exercises.zip. By using this mechanism the project has a minimal set of dependencies, which are handled by an Apache Ivy configuration (the Ivy plug-in for ant is dynamically downloaded and added to the installation during the build process).

Exercise 1: Generate the service stubs.

Examine the Apache ant build file (build.xml) includes in the exercise project. You will see a number of ant tasks, these can be grouped into:

  • Setting up the environment
  • Cleaning the build directories
  • Obtaining and unpacking the dependencies archive
  • Generation of JAX-WS stubs from a WSDL
  • Compiling of source code

To run the tasks described in the ant build file in Eclipse right-click on the build.xml file, select “Run As” → “Ant Build…” and select the required targets.

To build the JAX-WS examples we need to run two targets:

  1. jaxws-stubs: to generate the code stubs
  2. jaxws-compile: to compile the generate stubs and the client code.

To run these in Eclipse:

  1. Right-click on the build.xml file to bring up the menu
  2. Select “Run As” → “Ant Build…” to get the dialog describing the available targets
  3. Select the jaxws-stubs target to generate the stubs.
  4. Use the “Order…” button to put jaxws-stubs before compile
  5. Click the “Run” button to invoke the ant build.
  6. To ensure Eclipse recognises the generated code refresh the project:
    1. Right click on the project (e.g. EBIWS_Java_Exercises)
    2. Select “Refresh”

To run these targets from the command-line:

ant jaxws-stubs
ant jaxws-compile

Apache ant: WsImport task

Apache ant allows the addition of specific tasks via a plug-in mechanism. The WsImport task (http://jax-ws.java.net/nonav/2.2.5/docs/UsersGuide.html#3.1.2.1_Generate_a_Service_Endpoint_Interface_) supports the generation of JAX-WS stubs from a WSDL document and, if installed, can be used as an alternative to the generic task above.

Apache maven

A Maven plug-in is also available to generate JAX-WS code stubs from a WSDL document, see http://jax-ws-commons.java.net/jaxws-maven-plugin/ for details.

Using the Stubs

The stubs generated by wsimport are direct mappings of the interface and data types described in the WSDL into their Java equivalents. You may find looking at the generated code, WSDbfetch service documentation and http://www.ebi.ac.uk/ws/services/WSDbfetchDoclit?wsdl useful in the following section.

Import the generated classes into the program (assuming the uk.ac.ebi.webservices.wsdbfetch package):

import uk.ac.ebi.webservices.wsdbfetch.*;

To create a service proxy, with which you can interact with the service:

WSDBFetchDoclitServerService service = new WSDBFetchDoclitServerService();
WSDBFetchServer srvProxy = service.getWSDbfetchDoclit();

The methods of the service proxy (srvProxy) map to those defined in the WSDL, so to call the fetchData method of the WSDbfetch service we can use:

String result = srvProxy.fetchData("UNIPROT:ADH1A_HUMAN", "default", "raw");

The fetchData method returns a string containing the requested database entry, which can be output with:

System.out.println(result);

Then compile in the usual way:

  1. Using an IDE, such as Eclipse:
    • If “Build Automatically” is enabled the class is compiled when the source file is saved
    • Otherwise “Project”, “Build All” can be used to compile all source files in the project.
  2. Using Apache ant and the supplied build.xml file:
    ant jaxws-compile
  3. Using the Java commands from the command-line:
    javac uk/ac/ebi/webservices/wsdbfetch/*.java
    javac Dbfetch.java

And then run the program, to check it works:

  1. Using an IDE, such as Eclipse: right-click on the source file (e.g. Dbfetch.java), select “Run As” and “Java Application”.
  2. From the command-line:
    java Dbfetch

Exercise 2: WSDbfetch (document/literal SOAP)

The WSDbfetch web service (http://www.ebi.ac.uk/Tools/webservices/services/dbfetch) provides the same basic functionality as dbfetch, but through a collection of SOAP interfaces. Since JAX-WS does not support RPC/encoded SOAP services, the document/literal SOAP service has to be used.

Using the example WSDbfetch client (examples/soap/jaxws/Dbfetch.java) as a guide, use the service to fetch the UniProtKB entries with the accessions: P13569, P26361 and P35071, in fasta sequence format.

Sample solution: solutions/soap/jaxws/Q4Dbfetch.java

Exercise 3: WSDbfetch meta-data

The WSDbfetch service includes a number of meta-data methods which provide information about the service such as the names of the databases available, and the formats and styles which can be used with each database (see http://www.ebi.ac.uk/Tools/webservices/services/dbfetch).

Starting from the example client (examples/soap/jaxws/Dbfetch.java), use the getDbFormats() method of the WSDbfetch service determine what the available data formats are for the UniProtKB database.

Sample solution: solutions/soap/jaxws/Q5Dbfetch.java

Complex Data Structures

The methods in the WSDbfetch service all use simple string parameters. Many of the other EBI services use more complex input structures. For example NCBI BLAST (SOAP) requires a structure containing the various parameters and the input sequence to be passed to the run(email, title, params) method:

// Object factory for creating objects to be exchanged with the web service.
ObjectFactory objFactory = new ObjectFactory();
// Populate input parameters structure
InputParameters params = new InputParameters();
params.setProgram("blastp");
ArrayOfString databaseList = new ArrayOfString();
databaseList.getString().add("uniprotkb_swissprot");
params.setDatabase(databaseList);
params.setStype("protein");
params.setSequence(objFactory.createInputParametersSequence(">Seq1 Example search sequence\n"
  + "MKFLILLFNILCLFPVLAADNHGVGPQGASGVDPITFDINSNQTGPAFLTAVEMAGV"));
String email = "email@example.org"; // Your e-mail address
// Get the NCBI BLAST (SOAP) service proxy
JDispatcherService_Service service = new JDispatcherService_Service();
JDispatcherService ncbiblast = service.getJDispatcherServiceHttpPort();
// Submit the job
String jobid = ncbiblast.run(email, "", params);
System.out.println("Job Id: " + jobid);

Note: due to the sequence parameter being both optional (minOccurs=“0”) and nillable (nillable=“true”) it is mapped to a JAXBElement<String> object, for which an object is available from the ObjectFactory by using the createInputParametersSequence method, this allows all three of the possible states to be expressed:

  1. Explicit value, e.g. params.setSequence(objFactory.createInputParametersSequence(“UNIPROT:WAP_RAT”));
  2. Null value, e.g. params.setSequence(objFactory.createInputParametersSequence(null));
  3. No value, e.g. params.setSequence(null);

See Customizations for WCF Service WSDL section of the The WSIT Tutorial for details of how to modify this behavior by using a customized binding with wsimport.

The run(email, title, params) method returns a job identifier which can be used with the getStatus(jobId) method to get the status of the job (e.g. RUNNING, FINISHED or ERROR), the getResultTypes(jobId) method to get details of the available results for a finished job and the getResult(jobId, type) method to get the results of the job.

// Poll until job has finished
String status = "RUNNING";
while (status.equals("RUNNING")) {
  Thread.sleep(3000); // Wait 3 seconds
  status = ncbiblast.getStatus(jobid); // check job status
  System.out.println(status);
}
// If the job completed successfully...
if (status.equals("FINISHED")) {
  // Get the text result
  byte[] resultbytes = ncbiblast.getResult(jobid, "out", null);
  String result = new String(resultbytes);
  // Output the result
  System.out.println(result);
}

Exercise 4: NCBI BLAST (SOAP)

So far all the services we have looked at have been able to return the result in a relatively short period of time. This is not the case when running analytical tools, which in extreme cases may take days to return a result. So for these tools asynchronous methods have to be used, where the submission returns a job identifier which can be then used to check on the status of the job, and once it completes retrieve the results. The NCBI BLAST (SOAP) service, uses the NCBI BLAST suite to perform a sequence similarity search requires this approach. Examine the example client (examples/soap/jaxws/NcbiBlastSoap.java) and note the “run”, “getStatus” and “getResult” work flow.

Using the example client as a guide, perform an NCBI BLAST search with UniProtKB CFTR_MOUSE (uniprot:CFTR_MOUSE) against UniProtKB/SwissProt (uniprotkb_swissprot).

Sample solution: solutions/soap/jaxws/Q8NcbiBlastSoap.java

Exercise 5: NCBI BLAST (SOAP) meta-data

The NCBI BLAST (SOAP) service can return the result in a number of formats, modify your client to use the getResultTypes(jobId) method to discover the other available result types.

Sample solution: solutions/soap/jaxws/Q9NcbiBlastSoap.java

Proxies

In some environments it is necessary to configure an HTTP proxy before a client can connect to external services. JAX-WS supports the normal Java mechanisms for the configuration of proxies:

  1. Java system properties:
    • Provided to the JVM:
      java -Dhttp.proxyHost=proxy.example.org -Dhttp.proxyPort=8080 ExampleClientClass
    • Set in client code:
      System.setProperty("http.proxyHost", "proxy.example.org");
      System.setProperty("http.proxyPort", "8080");
  2. Using the java.net.Proxy and java.net.ProxySelector classes.

For details and examples see:

User-Agent

HTTP clients usually provide information about what they are, allowing services to handle specific clients differently if necessary, and giving service providers some information about how their services are being used. By default JAX-WS sets the HTTP User-Agent header (see RFC2616 section 14.43) to something like ”JAX-WS RI 2.1.6 in JDK 6”, where the version number (2.1.6) is the version of JAX-WS. If additional identification of the client is required a more specific product token (see RFC2616 section 3.8) should be added to the beginning of the User-Agent string. For example:

// Modify the user-agent to add a more specific prefix (see RFC2616 section 14.43)
String clientUserAgent = "Example-Client/1.0 (" + System.getProperty("os.name") + ")";
((BindingProvider)srvProxy).getRequestContext().put(
  MessageContext.HTTP_REQUEST_HEADERS,
  Collections.singletonMap("User-Agent",Collections.singletonList(clientUserAgent))
);

Where srvProxy is the service proxy object on which the User-Agent is to be modified.

Note: while the HTTP specification does not define a limit on the size of HTTP headers, web server implementations often do limit the maximum size of an HTTP header to 8KB or 16KB. If the server limit for an HTTP header is exceeded a “400 Bad Request” will be returned by the server.

Service End-point and Namespace

In cases where access is required to alternative instance of the web service, the end-point address for the service and possibly the XML namespace used for the SOAP messages will need to be modified. In JAX-WS these can be overridden when getting the service proxy object by specifying the a WSDL document describing the required end-point address and the required service XML namespace:

String srvWsdl = "http://wwwdev.ebi.ac.uk/ws/services/WSDbfetchDoclit?wsdl";
String srvXmlNamespaceUri = "http://www.ebi.ac.uk/ws/services/WSDbfetchDoclit";
String srvServiceName = "WSDBFetchDoclitServerService";
WSDBFetchDoclitServerService service = new WSDBFetchDoclitServerService(
  new java.net.URL(srvWsdl), 
  new javax.xml.namespace.QName(srvXmlNamespaceUri, srvServiceName));
WSDBFetchServer srvProxy = service.getWSDbfetchDoclit();

Sample Clients

Most SOAP Web Services at EMBL-EBI have sample clients which provide command-line access to the service and example code. For Java some of the clients are based on JAX-WS.

Document/literal SOAP

2) JAX-WS Reference Implementation - http://jax-ws.java.net/
3) Apache commons-cli - http://commons.apache.org/cli/
 
tutorials/06_programming/java/soap/jax-ws.txt · Last modified: 2013/06/21 09:33 by hpm
spacer
spacer