Developing Web Services with Open Source
A quick start for Web services technology
Source Code for this article
Over the past year, Web services have been positioned as a key enabler to application e-business integration. Many companies and vendors have made large investments in supporting the Web services development process. However, cost can pose a huge barrier for companies just beginning to investigate the value of Web services.
Development shops can
explore this emerging technology
without making a
large initial investment by
developing Web services with
open source platforms and development
tools. Open source refers
to the community of free applications
and systems being written
by developers around the world.
With open source, the source
code, its use, and redistribution
cannot be forbidden by any
organization.
The benefits of open source
include the ability to view the
source code, to see how features
are implemented, and to modify
the source to make changes. This allows
developers to port tools to other operating
systems and to build new products from
open source code. A key theme with open
source is flexibility, providing development
organizations with the source code and
the rights to modify it.
Web Services Development
Web services are built on a similar
open premise. Web services standards
such as SOAP and WSDL make software
components available to any
application developer. When combined
with open source tools, the Web
services development environment is
widely available at a very low cost.
This combination makes an attractive
model for the evaluation of Web
services as an enabling technology.
This article takes a look at both
the Web services development
process and the tools that can be
used to get started quickly. Through
the development of a prototype Web
service, you can quickly understand
how to evaluate these new technologies and
their use within production scenarios. Our
Web service provides weather forecast information
for a specified Zip Code. While there
are obviously many Web sites available for
retrieving weather, we wanted to deliver this
information as a Web service using SOAP.
The entire development was done on the
Linux platform. In our prototype, the Eclipse
environment with a Linux JDK was used to create
the Java components. The Apache Axis platform
was used to easily expose this Java component
as a Web service. Apache Ant was then
used for building and deploying the Web service,
and PushToTest TestMaker for testing it.
Setting up the Environment
The first step in developing our service
was the selection of a Linux distribution.
While there are many Linux distributions
available, we selected Debian Linux
(www.debian.org). Debian is one of the most
vendor-neutral Linux distributions, managed
by the developer community. This distribution
also has a strict open source-only policy,
and does not contain any license-restricted
code. Debian Linux has a successful model
for creating high-quality, portable, and stable
releases.
To deliver this service, we need a data
source that can manage the weather forecast
information. For this example, we decided to
model the forecast information in a SQL database.
The two most popular open source databases
on the market today are MySQL and
PostgreSQL. We selected MySQL
(www.mysql.com) for this development primarily
because of its ease-of-use and speed.
After installing the product, we created the
necessary tables for the Weather application.
We designed two simple tables, one to maintain Zip Code information and another to
hold the weather forecasts.
Another step required for the Java development
was to select an appropriate Java
Development Kit (JDK). The JDK was required
to run a number of components in this example,
including Eclipse, Apache Axis, and the
application itself. The most popular Linux
JDKs on the market today are the J2SE SDK
from Sun, the Blackdown JDK (www.blackdown.org), and BEA WebLogic JRockit
(www.bea.com). JRockit was selected for this
example.
Developing a Java Application with Eclipse
Next we chose an integrated development
environment (IDE). The IDE was used to
develop the Java application for the Web service.
Open source Java developers now have
several choices when considering IDEs. Two
of the more popular open source IDEs are
NetBeans (www.netbeans.org) and Eclipse
(www.eclipse.org). The Eclipse Platform was
chosen because of its extensibility. This platform
allows tool builders to independently
develop tools that integrate with other developer
tools. Figure 1 shows a screenshot from
the Eclipse environment.
Eclipse operates with a set of views called
perspectives. A perspective manifests itself in
the selection and arrangement of editors and
views displayed on the screen. For example,
while developing a Java application, Eclipse
changes to the Java perspective. This perspective
sets up the GUI with the proper views and
editors for developing Java applications. In
addition, Eclipse includes a number of wizards
to assist in the development of Java components.
Figure 2 shows the wizard used for
creating the base Weather class.
Next we added the code for the Weather
service. The application takes a Zip Code and
looks up the weather forecast for that area in
the MySQL database using JDBC. Listing 1 is a
partial listing of the code that retrieves this
information (the code for this article is online
at www.sys-con.com/webservices/sourcec.cfm).
Next we created the Forecast class. We created
this class as a Value Object to hold the
forecast information for the service. It provided
a cleaner and more usable business interface
for the caller. Rather than returning a
simple String, we can return a more complex
type describing the forecast information (see
Listing 2).
We found that Eclipse brought together all
of the tools we needed to successfully develop
the service. Overall, Eclipse proved to be a very
robust yet simple platform for building the Java
components for the application. It has most of
the same functionality as any other commercial
tool, but it's also open source.
Installing and Configuring the Web Services Runtime
Since Web services are software components
that are exposed to other applications
via XML over HTTP, we needed a J2EE and
Web services container in which to run our
new service. For our runtime environment, we
used Jakarta Tomcat (http://jakarta.apache.org/tomcat) and a Web services tool kit,
Apache Axis (http://ws.apache.org/axis).
Tomcat was downloaded from the Apache
Web site. Once installed, we used a plug-in to
Eclipse to start and stop the Tomcat server. We
created our own Eclipse perspective for this so
that we could reuse it for other applications
running on Tomcat (see Figure 3).
In addition to the J2EE Web container, we
needed a Web services environment. The Axis
SOAP implementation includes a set of tools
that help you build SOAP clients and servers.
It provides support for both sending and
receiving SOAP requests. We downloaded
Apache Axis from www.apache.org/axis and
used the latest release because of some added
enhancements that support JAX-RPC and
Java-to-WSDL mappings. Once installed, we
tested Axis by viewing the URL http://localhost:
8080/axis from Mozilla (see Figure 4).
Creating the Web Service Using Apache Axis
Our next major step was to create the
Web service interface (WSDL) and related
server-side bindings. A WSDL is an XML
document that describes the data, messages,
and operations that are exposed for a
given service. The bindings allow us to easily
map the WSDL interface to any back-end
components.
Two approaches can be taken in creating
a WSDL document. It can be created from
scratch and later mapped to a set of backend
components. Or, a developer can start
with their business logic and have the
WSDL created automatically. We usually
recommend starting from the WSDL for
increased flexibility and probability. For
this simple scenario, we used the automatic
WSDL generation feature. Within Apache
Axis, this can be accomplished through the
Java2WSDL utility class:
java org.apache.axis.wsdl.Java2WSDL -o
Weather.wsdl -l "http://localhost:
8080/axis/services/weather" -n
urn:weather -p"Weather" urn:weather
weather.Weather
Listing 3 shows the WSDL generated
running this command. It includes a set of
data types, messages, operations, and SOAP
bindings for the service.
The WSDL first describes the XML type
used to represent the Forecast information.
This is followed by the specific operations
for the service, in our case getWeather. This
operation is a basic request/response message,
modeled with one input and one output
message. The WSDL also contains the
SOAP binding and service binding information.
This binding specifies the URL location
for accessing the service.
The next major step was to create the
server-side bindings for the Web service.
These bindings allow us to easily map the
WSDL interface to the back-end Java components.
Within Apache Axis, this is accomplished
through an implementation class
and a deployment descriptor. The following
illustrates the invocation of the WSDL2Java
class to generate these components:
$ java org.apache.axis.wsdl.WSDL2Java -
o . -s -p weather.ws Weather.wsdl
The WeatherSoapBindingImpl.java file
generated contains an empty implementation
for the service. We had to modify this
code with the appropriate invocations to
our original Weather class (see Listing 4).
We also had to create a new version of
the Forecast class that implemented
java.io.Serializable so that the data could be
serialized as an XML stream. After that, we
just needed to compile our code and generate
a JAR file containing all of the class files.
We copied the JAR into the Apache Axis lib
directory so that Axis could locate the code.
The final step in the service creation
process was to register the Web service with
Apache Axis. Axis provides a deployment
tool (AdminClient) to do this. The deployment
descriptor specifies the service being
deployed, the operations being exposed,
and the mapping to the back-end implementation
class. Listing 5 is a partial listing
of the deploy.wsdd generated.
At this point, we successfully created,
packaged, and deployed the service. We
verified service deployment by viewing the
list of services in a browser (see Figure 5).
Implementing a Build Process with Ant
The last section walked through the various
steps required to compile, package,
and deploy the Web service. This can be a
very time-consuming process, especially if
you must continually rebuild your Web
service during testing. This is where a
robust and automated build process can be
very helpful in enhancing developer
productivity.
One of the more popular open source
build tools available today is Apache Ant.
You can think of Ant as a next-generation
Make utility, with the key difference that
Ant is based on Java and XML. With Ant,
you can compile and execute Java applications,
create JAR files, and deploy files to
Web directories. Apache Ant can also be
used to assist in the generation of many of
the Web services components.
While Ant can be downloaded from the
Apache Web site, we decided to take advantage
of the built-in integration between
Eclipse and Ant. This integration allows you
to take an Ant build file and run selected
build targets. Supplied Eclipse plug-ins also
provide a more robust editing environment
for creating Ant build files (see Figure 6).
We focus here on how Ant was used to
create the Java server-side bindings from
the WSDL, and how that code is packaged
and deployed to Apache Axis. Listing 6 provides
a partial listing of the ANT file that
was developed for this purpose.
In an Ant build file, a number of targets
can be executed. A target represents a specific
step in the build process. Our build
includes an Ant target for creating the Java
bindings from the WSDL. The build file also
includes a target to compile the code using
the <javac> tag. In the listing, we specify
this tag, followed by the directory to compile
and the CLASSPATH to use.
Once the code is compiled, we can package
and deploy the service. In the ANT
build file, we use the <jar> tag to create the
Java archive. In this section, we specify the
name of the JAR file to create, and the list of
class files to package. We used the <copy>
tag to copy the library to the Apache Axis
lib directory. Finally, the AdminClient utility
is invoked to register the deployment
descriptor.
After developing the complete
build.xml file, we can execute specific
build targets. From within the Eclipse
environment, you can select specific targets
to run (see Figure 7).
Overall, the use of ANT, combined with
the integration into the Eclipse environment,
provided a clean and elegant way to
automate the build process for Java applications.
It also provided an efficient mechanism
to quickly build (and rebuild) the various
Web services components.
Testing the Service
After deploying the Web service, the next
step was to contact the Web service via a
client proxy. A client proxy is a piece of code
that communicates directly with the Web
service, encapsulating the SOAP processing
logic, and shielding the developer from having
to write this code directly. Axis provides a
mechanism for automatically creating the
client proxy code through the WSDL2Java utility.
We used the helper class, WeatherServiceLocator, that Axis automatically generated to
locate the Weather Web service. Next, we
inserted the code to bind to the getweather
method in the WeatherServiceLocator. We
communicated with the Web service to get a
Forecast object with the appropriate information
(see Listing 7).
To debug our Web service, we can use
either the Axis tcpmon or SOAP Monitor utilities.
tcpmon listens for connections on a
given port on the localhost and forwards
incoming messages to another port on
another server. By inserting itself between
the two ports, tcpmon can show you all
incoming and outgoing SOAP messages. To
use the tool, it was necessary to change our
code to bind to port 8081 instead of 8080.
Figure 8 shows how tcpmon can monitor
SOAP traffic.
Axis also comes with a SOAP Monitor utility
that can be used to monitor SOAP traffic
without changing the port configuration.
This utility is loaded as a Java applet within a
browser window (http://localhost:8080/axis/
SOAPMonitor). Overall, developers will find
these utilities helpful in debugging a Web
service, especially in cases where you get an
exception or SOAP fault. You can determine
whether the client properly constructed the
SOAP message for the service.
Web services testing is another important
development concern. While there are
a number of open source testing tools
available, such as JUnit and Anteater, we
selected PushToTest TestMaker
(www.pushtotest.com). This tool allows
you to test the functionality, scalability,
and performance of a Web service. The primary
advantage of using TestMaker is its
user-friendly development environment
for creating test scripts. It comes with an
object-oriented scripting language, Jython,
as well as a library for communicating
with Web services.
When we used this tool, we encountered
some issues with getting TestMaker to understand
the Forecast XML type returned by the
service. We had to add some additional logic
to serialize the XML schema type into the
JavaBean representation (see Listing 8).
Once the service is fully deployed and
tested, a developer will need to consider
monitoring the service for availability. This is
where management tools are helpful, if not
essential. For example, you could use the HP
OpenView SPI for Apache Axis, which provides
a mechanism to track the availability of
the SOAP server. The HP OpenView
Transaction Analyzer (OVTA) product, used
to diagnose performance bottlenecks, is
being enhanced to support Web services
built with Apache Axis.
In the End
While we encountered several technical
hurdles with this new development environment,
we found these tools worked well
together and were a boost to our Web services
development productivity. In fact, we were
quite surprised by some of the integration we
found in Eclipse with Tomcat, Apache Axis,
and Ant. We found the ability to locate, obtain,
install, and use open source development
environments and tools to be very straightforward.
Not only did these tools work "out of the
box," but the quality was sufficient for our
development purposes.
Development organizations need to quickly
start using Web services technology, but
can't always afford to make significant early
investments in tools that ultimately prove critical.
However, the open source model helps
these groups by allowing them access to a
low-cost solution for Web services development.
We were able to demonstrate a complete
development process for Web services
leveraging only open source tools. This should
go a long way towards helping development
teams get acquainted with Web services programming.
About the Authors
Chris Peltz and Claire Rogers are senior software consultants
in HP's Developer Resources Organization (http://devresource.
hp.com).
chris.peltz@hp.com
claire.rogers@hp.com
Developing Web Services with Open Source by Chris Peltz & Claire Rogers
WSJ Vol 03 Issue 12 - pg.12
Listing 1
public class Weather extends Object {
public static Forecast getWeather(String zip)
throws Exception {
Connection conn = null;
Forecast f = null;
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn=DriverManager.getConnection("jdbc:mysql://localhost/weatherdb",
"hpuser","hppwd");
String select = "select * from zipcode where zipcode = ?";
PreparedStatement stmt = conn.prepareStatement(select);
stmt.setString(1,zip);
ResultsSet rs = stmt.executeQuery();
rs.next();
String city = rs.getString("city");
String state = rs.getString("state");
String date = "2003-04-02";
select = "select * from forecast where zipcode = ? and dt = ?";
stmt = conn.prepareStatement(select);
stmt.setString(1,zip);
stmt.setString(2,date);
rs = stmt.executeQuery();
rs.next();
f = new Forecast(zip,city,state,date, rs.getString("forecast"),
rs.getShort("high"),
rs.getShort("low"), rs.getByte("precip") );
return f;
}
}
Listing 2
public class Forecast {
public Forecast(String z, String c, String s, String d, String f, short h, short l,
byte p) {
zip = z;
city = c;
state = s;
date = d;
forecast = f;
hi = h;
low = l;
precip = p;
}
}
Listing 3
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions ...">
<wsdl:types>
<schema ...>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="Forecast">
<sequence>
<element name="zip" nillable="true" type="xsd:string"/>
<element name="city" nillable="true" type="xsd:string"/>
<element name="state" nillable="true" type="xsd:string"/>
<element name="date" nillable="true" type="xsd:string"/>
<element name="forecast" nillable="true" type="xsd:string"/>
<element name="hi" type="xsd:short"/>
<element name="low" type="xsd:short"/>
<element name="precip" type="xsd:byte"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="getWeatherResponse">
<wsdl:part name="getWeatherReturn" type="tns2:Forecast"/>
</wsdl:message>
<wsdl:message name="getWeatherRequest">
<wsdl:part name="in0" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="Weather">
<wsdl:operation name="getWeather" parameterOrder="in0">
<wsdl:input name="getWeatherRequest" message="impl:getWeatherRequest"/>
<wsdl:output name="getWeatherResponse" message="impl:getWeatherResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="weatherSoapBinding" type="impl:Weather">
...
</wsdl:binding>
<wsdl:service name="WeatherService">
<wsdl:port name="weather" binding="impl:weatherSoapBinding">
<wsdlsoap:address location="http://localhost:8080/axis/services/weather"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Listing 4
public weather.ws.Forecast getWeather(java.lang.String in0)
throws java.rmi.RemoteException {
weather.Weather w = new weather.Weather();
weather.Forecast f = w.getWeather(in0);
weather.ws.Forecast f1 = new weather.ws.Forecast();
f1.setZip(f.zip);
f1.setCity(f.city);
f1.setState(f.state);
...
return f1;
}
Listing 5
<service name="weather" provider="java:RPC" style="rpc" use="encoded">
<parameter name="wsdlTargetNamespace" value="urn:weather"/>
<parameter name="wsdlServiceElement" value="WeatherService"/>
<parameter name="wsdlServicePort" value="weather"/>
<parameter name="className" value="weather.ws.WeatherSoapBindingImpl"/>
<parameter name="wsdlPortType" value="Weather"/>
<operation name="getWeather" qname="operNS:getWeather"
xmlns:operNS="urn:weather" returnQName="getWeatherReturn"
returnType="rtns:Forecast" xmlns:rtns="http://weather" >
<parameter name="in0" type="tns:string" xmlns:tns="http://www.w3.org/2001/XMLSchema"/>
</operation>
...
</service>
Listing 6
<target name="wsdl2java" depends="java2wsdl" description="Create Java Bindings">
<axis-wsdl2java
output="${proj.dir}"
serverside="true"
url="${proj.dir}/Weather.wsdl">
</axis-wsdl2java>
</target>
<target name="compilews" depends="wsdl2java" description="Compile Web Services">
<javac srcdir="${ws.dir}"
destdir="${build.classes.dir}"
classpathref="axis.classpath">
</javac>
</target>
<target name="deploy" depends="compilews" description="Deploy WS">
<jar destfile="${proj.dir}/Weather.jar">
<fileset dir="${proj.dir}/weather">
<include name="**/*.class"/>
</fileset>
</jar>
<copy file="${proj.dir}/Weather.jar" todir="${axis.web-inf}"/>
<axis-admin xmlfile="${proj.dir}/weather/ws/deploy.wsdd"/>
</target>
Listing 7
public class WeatherClient {
public static void main(String [] args) {
WeatherService service = new WeatherServiceLocator();
Weather weather = service.getweather();
Forecast forecast = weather.getWeather(args[0]);
System.out.println("Forecast:" + forecast.getForecast());
}
}
Listing 8
# setup protocol
protocol = ProtocolHandler.getProtocol("soap")
body = SOAPBody()
protocol.setBody(body)
# define the location of the web service
protocol.setHost("localhost")
protocol.setPath("axis/servlet/AxisServlet")
protocol.setPort( 8081 )
# Send a request to the getWeather method in the weather web service
body.setTarget("weather")
body.setMethod("getWeather")
body.addParameter( "zip", String, "80538", None )
# create a bean serializer
beanSer = BeanSerializer()
qName = QName("http://weather", "Forecast")
protocol.setMapTypes( Constants.NS_URI_SOAP_ENC, qName, Forecast, beanSer, beanSer )
# print result
for i in range(100):
response = protocol.connect()
print "TIME: ", Long(response.getTotalTime()).toString()
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com