<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d9519466\x26blogName\x3dthe+spkydog+koop\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dTAN\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttps://spkydog.blogspot.com/search\x26blogLocale\x3den_US\x26v\x3d2\x26homepageUrl\x3dhttp://spkydog.blogspot.com/\x26vt\x3d-4534400202552370894', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>

Monday, December 29, 2008

Tutorial - Writing a SOAP web service client in Java in 20 minutes or less

So you don't know SOAP from WSDL? Whether you're coming from the RESTful school when it comes to building out web services, or you've simply managed to not get involved in web services altogether, here's a really simple tutorial describing how you can access an existing SOAP web service from Java in less than 20 minutes.

Preliminaries

To get started, we'll visit www.xmethods.net and find an interesting public web services that our Java client will attempt to access. For this tutorial, we'll settle on CDYNE's Free Weather Web service. Next we'll assume you have a recent vintage Java SE Developer Kit installed on your machine. Finally, we will also assume you have a recent version of Apache ant installed in your development environment, and that you are familiar building projects using ant.

Installing Apache Axis

You'll need to install a recent copy of Apache Axis. At the time of writing, we're using version 1.4. Axis is the Apache Web Services Project - an open source implementation of W3C SOAP and related specifications. It comes in both a C++ flavor, as well as Java so be sure to download and install the latter. Download the Apache Axis archive and unpack it on your local disk. We'll assume the root directory of your Axis installation is BASEDIR in the discussion that follows.

Generating Java Bindings for the Service

You'll notice that each public web service listed on www.xmethods.net has an associated WSDL description. Simply put, WSDL (pronounced "whiz-del") is an XML language that describes the interfaces of a web service. Since we want our Java client to access the CDYNE Free Weather service, we'll save a copy of its WSDL file to our local disk in a file named Weather.wsdl.

Apache Axis includes a convenient tool called WSDL2Java that lets you automatically generate the necessary Java bindings from a WSDL description. If you've included the jar files included in BASEDIR/lib in your classpath you can run this tool on your WSDL file as follows:
% java org.apache.axis.wsdl.WSDL2Java Weather.wsdl
We can also accomplish this with a simple ant build.xml file:
<project name="axisSamples" default="run-client">

<property name="librarydir" value="C:\axis-1_4\lib"/>

<path id="libraries">
<fileset dir="${librarydir}">
<include name="*.jar"/>
</fileset>
</path>

<target name="run-wsdl2java">
<java fork="true" dir="src" classname="org.apache.axis.wsdl.WSDL2Java" classpathref="libraries">
<arg line="../Weather.wsdl"/>
</java>
</target>
Either way, after successfully running the WSDL2Java tool you'll find the generated Java bindings for the services described in the WSDL file in the same directory. The generated classes will be found within a package hierarchy that was generated using the target namespace used within the WDSL file. In our example, the package will be com.cdyne,ws.WeatherWS.

Writing the Java Client

Next, we will write a simple Java client that utilizes the classes we generated from the WSDL file in the previous step. We'll begin by browsing through the generated code. Take a look at WeatherLocator.java. This is the class we'll use to bootstrap our client to get an interface to the Java stub that implements the interface to the remote web service. Looking at the class implementation, you'll notice this method:
   public com.cdyne.ws.WeatherWS.WeatherSoap getWeatherSoap() throws javax.xml.rpc.ServiceException {
java.net.URL endpoint;
try {
endpoint = new java.net.URL(WeatherSoap_address);
} catch (java.net.MalformedURLException e) {
throw new javax.xml.rpc.ServiceException(e);
}
return getWeatherSoap(endpoint);
}
This method returns an instance that implements the interface com.cdyne.ws.WeatherWS.WeatherSoap. If we take a look at the interface (in WeatherSoap.java) we can see the details of the operations the SOAP weather service makes available:
public interface WeatherSoap extends java.rmi.Remote {

/**
* Gets Information for each WeatherID
*/
public com.cdyne.ws.WeatherWS.WeatherDescription[] getWeatherInformation() throws java.rmi.RemoteException;

/**
* Allows you to get your City Forecast Over the Next 7 Days,
* which is updated hourly. U.S. Only
*/
public com.cdyne.ws.WeatherWS.ForecastReturn getCityForecastByZIP(java.lang.String ZIP) throws java.rmi.RemoteException;

/**
* Allows you to get your City's Weather, which is updated hourly.
* U.S. Only
*/
public com.cdyne.ws.WeatherWS.WeatherReturn getCityWeatherByZIP(java.lang.String ZIP) throws java.rmi.RemoteException;
}
That's essentially all we need to know to write our simple Java client (TestClient.java) that accesses the remote web service:
import com.cdyne.ws.WeatherWS.*;
import java.util.Calendar;

/**
* @author spkydog (http://spkydog.blogspot.com)
*
*/
public class TestClient {

public static void main(String[] args) {

try {
Weather wservice = new WeatherLocator();
WeatherSoap wsrv = wservice.getWeatherSoap();
ForecastReturn retVal = wsrv.getCityForecastByZIP("49426");

if (retVal.isSuccess()) {

System.out.println("The weather forecast for "
+ retVal.getCity() + ", "
+ retVal.getState() + " is:\n ");

Forecast[] forecasts = retVal.getForecastResult();
for(Forecast f : forecasts) {

Calendar date = f.getDate();
System.out.println(date.get(Calendar.DAY_OF_MONTH)
+ "/" + date.get(Calendar.YEAR)
+ ": " + f.getDesciption());
}

}

} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Notice that WSDL2Java also generates all the various types used as input and output to the methods supported by the web service. In this case, we have a variety of types, of which we use two in the simple client above (ForecastReturn.java and Forecast.java)

Building/Running the Java Client

Once again, assuming that the axis jars are in our classpath, and our client and generated code is all in a sub-directory named src, we can compile our test client by entering the following command at the console:
% javac src/*.java src/com/cdyne/ws/WeatherWS/*.java
We can also build the code by adding a compile task to our build.xml file:
<target name="compile" depends="run-wsdl2java">
<javac srcdir="src">
<classpath>
<path refid="libraries"/>
</classpath>
</javac>
</target>
We can run the client by entering the following command at a commandline console:
% java TestClient
Or, if we haven't bothered to add the axis jar files to our environment's CLASSPATH variable, we can simply invoke the client via ant by adding this task:
<target name="run-client" depends="compile">
<java fork="true" dir="src" classname="TestClient" classpathref="libraries">
<classpath path="src"/>
</java>
</target>
If all worked as planned, the client prints out the weather forecast ranging from yesterday to six days into the future:
The weather forecast for Hudsonville, MI is:

28/2008: Partly Cloudy
29/2008: Mostly Cloudy
30/2008: Mostly Cloudy
31/2007: Partly Cloudy
1/2008: Mostly Cloudy
2/2008: Mostly Cloudy
3/2008: Mostly Cloudy
That's all there is to it! A zip archive with the complete source code and ant build.xml is available for download here.