Clean up your wire protocol with SOAP, Part 1 An introduction to SOAP basics
part 2 Use Apache SOAP to create SOAP-based applications
Over the past couple of years, the Simple Object Access Protocol (SOAP) has taken off at rocket speed. A solid understanding of SOAP concepts has become essential for any strong software professional, especially software architects. The reason is quite simple. SOAP provides the foundation for one of the most exciting developments in the software industry today: Web services. Web services are exciting because they take application integration and interoperability to a new level never possible before, even with Java and J2EE (Java 2 Platform, Enterprise Edition).
To summarize, SOAP offers the following:
- An XML-based wire protocol, which is thus Web/firewall friendly
- A universally accepted W3C (World Wide Web Consortium) standard backed by all major and minor market players, including Microsoft, Sun Microsystems, IBM, and HP
Before diving into this article, you might want to review my previous JavaWorldseries, "Clean Up Your Wire Protocol with SOAP," where I explain the basics of SOAP and why it proves so critical to the future of distributed computing:
- Part 1. An introduction to SOAP basics
- Part 2. Use Apache SOAP to create SOAP-based applications
- Part 3. Create SOAP services in Apache SOAP with JavaScript
- Part 4. Dynamic proxies make Apache SOAP client development easy
In those articles, I focused on how developers could use Apache SOAP to build SOAP-based projects. Since then, Apache has completely rebuilt its SOAP implementation, creating a new project called Axis. In this article, I provide a high-level overview of the improvements Axis targets. I also show how to create and deploy a simple Web service with Axis.
What is Axis?
All software developers understand the importance of software toolkits; they prove essential to ensuring high developer productivity in this era of rapid application development. Coding with SOAP is no different. Although you could handcraft all your XML-based SOAP messages, you would probably want to use a SOAP toolkit to speed your development. After all, you don't handcode all your RPC (remote procedure call) messages in bits and bytes; why should SOAP messages be any different?
One such toolkit is available for SOAP. Apache SOAP's first generation was based on SOAP4J, IBM's donated codebase. I covered this excellent implementation in Parts 2 through 4 of my earlier series. As good as it was, Apache SOAP is now better. Axis is not just a rewrite of Apache SOAP, but a complete re-architecture. For Axis, Apache plans two alpha releases with partial functionality, a beta release with complete functionality, and a final release, Axis 3.0, which will supersede Apache SOAP 2.2. Alpha 1 was released in August 2001 and alpha 2 was released in September 2001. Though alpha 3 was issued in December 2001, this article focuses on the alpha 2 release (which features the same functionality as alpha 3).
When complete, Axis will:
- Support SOAP 1.1, just as Apache SOAP 2.2 does. For example, Axis will completely support the SOAP concept of
mustUnderstand
headers. Axis's final release will have a few SOAP 1.2 features as well as partial support for pluggable XML protocols. - Likely prove much faster and more resource efficient than Apache SOAP, since it uses SAX (Simple API for XML) instead of DOM (Document Object Model). SAX allows lazy parsing of XML documents, which in many cases is more efficient -- especially when the entire XML document does not need to be parsed or kept in memory for long time periods.
- Have a clean and simple abstraction for designing transports -- i.e., senders and listeners for SOAP over various protocols such as SMTP (Simple Mail Transfer Protocol), FTP, message-oriented middleware, and so on. Also, the engine's core will be completely transport independent.
- Automatically generate WSDL (Web Services Description Language) from deployed services. The Axis alpha 2 version also comes with the wsdl2java tool for building Java proxies and skeletons from WSDL documents. Thus, you not only get the WSDL for an Axis-deployed service, but you can also build stubs and skeletons from the WSDL for extremely easy client code development. Note that the WSDL that feeds into the wsdl2java tool can originate from any source as long as it adheres to the WSDL specification. I'll show you an example of using this feature later.
- Support EJB (Enterprise JavaBeans) deployment as services. This resembles a feature provided by some application servers, such as BEA WebLogic Server.
- Feature improved deployment support and the ability to drop Java files into a deployment directory and expose the classes as services. I'll show you an example of this later.
- Better interoperate with Microsoft's SOAP implementation and .Net services. Over the past year, Apache and Microsoft have undergone several iterations of their SOAP implementations; with each iteration, they become more interoperable with each other. For details, see the summary of the last Apache/Microsoft interoperability meeting.
Although I use the future tense in the bullet points above, the alpha 2 release already includes many of these features.
Now, let's install Axis and create a simple service with it.
Install Axis
Although the Axis installation guide is fairly straightforward, these instructions will further ease the process:
First, ensure you have a Web server installed. I use Tomcat. If you have another Web server, you can still download Tomcat's latest version (version 4.0.1, at the time of this publication) fromhttp://jakarta.apache.org/tomcat/index.html. Unzip the downloaded zip file into your C drive, or your preferred drive. (Note that I refer to the C drive in all my instructions.) You should see Tomcat installed in the directory C:\jakarta-tomcat-4.0.1
(if you have a different version, substitute your version number in place of 4.0.1
). I will refer to this directory as TOMCAT_HOME
.
Second, download Axis's latest release from http://xml.apache.org/axis/index.html. Unzip this zip file into your C drive as well. Axis should now be installed in the directory C:\axis-1_0
(for version 1.0, alpha 2). I will refer to this directory asAXIS_HOME
.
Third, copy the Axis folder from AXIS_HOME\webapps
into TOMCAT_HOME\webapps
.
Now copy xerces.jar
from your Xerces installation into theTOMCAT_HOME\webapps\axis\WEB-INF\lib
directory. If you don't have Xerces, you can download it for free from http://xml.apache.org/xerces2-j/index.html. All you have to do is download the zip file and unzip it into your C drive. xerces.jar
will be in the root of your Xerces installation -- for example, C:\xerces-1_4_4
.
Finally, set up a context in the server.xml
file in the directory TOMCAT_HOME\conf
by adding this line:
<Context path="/axis" docBase="axis" debug="0" reloadable="true"/>
That's it. Axis is now installed and ready to use.
Create the Web service
Like the service in "Clean Up Your Wire Protocol with SOAP, Part 2," the Web service that we will create here is the "Hello World" of Web services. As you can see below, it is a class that has one method, sayHelloTo()
, which takes a name as its only parameter and returns a customized hello message. Note that the class is not littered with any Axis-specific code:
public class HelloServer { public String sayHelloTo(String name) { System.out.println("sayHelloTo(String name)"); return "Hello " + name + ", How are you doing?"; } }
Deploy the Web service the easy way
To deploy this Hello World Web service, just copy and paste the HelloServer.java
file into the TOMCAT_HOME\webapps\
directory and change its extension from .java
to .jws
. That's all there is to it; the Web service is deployed and ready for use. And you didn't even have to compile the Java file! This is Axis feature number 6 (described above) in action.
When a client invokes a service deployed in this manner, Axis will automatically locate the file, compile the class, and convert SOAP calls correctly into your service class's Java invocations. As you will see in the next section, the service name corresponds to the name of the .jws
file. The magic that allows the Web server to invoke the Axis engine (i.e., servlet) when a .jws
file is requested is located in theTOMCAT_HOME\webapps\axis\WEB-INF
directory. This file's appropriate section is shown below:
<servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>*.jws</url-pattern> </servlet-mapping>
Based on the above configuration information, whenever Tomcat -- or any J2EE-compliant Web server -- encounters a .jws
file in the Axis context (set up above during installation), it will invoke the AxisServlet
. The AxisServlet
then performs its magic as described above.
Create the client
Now let's create a simple client that we'll use to test the service. The code to do that is shown here:
package javaworld.axis; import org.apache.axis.client.ServiceClient; public class Client1 { public static void main(String[] args) throws Exception { String endpoint = "http://localhost:8080/axis/HelloServer.jws"; ServiceClient client = new ServiceClient(endpoint); String ret = (String)client.invoke("","sayHelloTo",new Object [] {args[0]}); System.out.println(ret); } }
As with Apache SOAP, the client code is a bit more involved than the server code. But it is much simpler than the equivalent Apache SOAP client code, which is also shown below for reference. To understand the code below, please refer to "Clean Up Your Wire Protocol with SOAP, Part 2."
package javaworld.axis import java.net.URL; import java.util.Vector; import org.apache.soap.SOAPException; import org.apache.soap.Constants; import org.apache.soap.Fault; import org.apache.soap.rpc.Call; import org.apache.soap.rpc.Parameter; import org.apache.soap.rpc.Response; public class Client { public static void main(String[] args) throws Exception { URL url = new URL("http://localhost:8080/apache-soap/servlet/rpcrouter"); String name = args[0]; // Build the call. Call call = new Call(); call.setTargetObjectURI("urn:Hello"); call.setMethodName("sayHelloTo"); call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC); Vector params = new Vector(); params.addElement(new Parameter("name", String.class, name, null)); call.setParams(params); // Invoke the call. Response resp = null; try { resp = call.invoke(url, ""); } catch( SOAPException e ) { System.err.println("Caught SOAPException (" + e.getFaultCode() + "): " + e.getMessage()); System.exit(-1); } // Check the response. if( !resp.generatedFault() ) { Parameter ret = resp.getReturnValue(); Object value = ret.getValue(); System.out.println(value); } else { Fault fault = resp.getFault(); System.err.println("Generated fault: "); System.out.println (" Fault Code = " + fault.getFaultCode()); System.out.println (" Fault String = " + fault.getFaultString()); } } catch(Exception e) { e.printStackTrace(); } } }
It should be obvious that Axis does a much better job shielding the client developer from the details. In the simplest case (as the one in this article), you need to create only an instance of the classorg.apache.axis.client.ServiceClient
, which requires the service endpoint as its constructor parameter. The endpoint here is http://localhost:8080/axis/HelloServer.jws
, since (1) the Web server is on the same machine as the client; (2) Tomcat by default listens for HTTP requests on port 8080; and (3) the service is deployed as HelloServer.jws
. Finally, you invoke any method on the service by simply calling the invoke()
method on the ServiceClient
instance. At the very least, invoke()
requires both the method's name on the service to invoke, and an Object
array of parameters.
Test the service
To test the service, begin by compiling the client using the following command sequence. Note that axis.jar
must be included in the CLASSPATH
to successfully compile the client application:
set CLASSPATH=AXIS_HOME\lib\axis.jar javac Client1.java
Start Tomcat if it's not already started. To start Tomcat, run the startup.bat
batch file located in TOMCAT_HOME\bin\
. Next, run the client application:
set CLASSPATH=C:\dev\;AXIS_HOME\lib\axis.jar;AXIS_HOME\lib\log4j-core.jar java javaworld.axis.Client1 John
This time, in addition to axis.jar
, you must also include log4j-core.jar
, which is the jar file that contains classes used by axis.jar
's classes for logging. Also, C:\dev
is the directory containing the javaworld
package, so you must include it in the CLASSPATH
too.
Deploy the Web service the flexible way
Deploying the Web service as a .jws
file works for simple services such as the one in this article. However, this approach fails to meet most commercial Web services' flexibility requirements, such as the ability to specify custom type mappings or create handler chains. Instead, most deployments will probably use deployment files such as the one shown below for our Web service:
<m:deploy xmlns:m="AdminService"> <service name="HelloServer" pivot="RPCDispatcher"> <option name="className" value="javaworld.axis.HelloServer"/> <option name="methodName" value="sayHelloTo"/> </service> </m:deploy>
The deployment XML shown above is fairly simple and does not use or demonstrate any of the advanced features allowed in such deployment files. However, let's say that I wanted to define a logging mechanism in the form of an Axis handler -- handlers follow the Chain of Responsibility design pattern (see Resources). I could do this by simply adding the following section to the deployment file:
<!-- define a logging handler configuration --> <handler name="logger" class="loggers.LogHandler"> <option name="filename" value="HelloServer.log"/> </handler>
As I mentioned earlier, Axis offers a much more flexible and capable deployment process. In the previous section, I illustrated how simple deploying Web services in Axis can be. In this section, I give you a peek into Axis's more flexible and capable aspects.
The configuration above is self-explanatory. I have basically created a new service that uses the class javaworld.axis.HelloServer
and exposes the sayHelloTo()
method. If I want to expose more methods, I would replace the single sayHelloTo()
method name with a space-delimited list of method names. However, don't get too attached to this XML descriptor format: in Axis's final release, this XML will change to the Axis Web Service Deployment Descriptor (WSDD) format. The same configuration in WSDD format is shown below for reference:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="HelloServer" provider="java:RPC"> <parameter name="className" value="javaworld.axis.HelloServer"/> <parameter name="methodName" value="sayHelloTo"/> </service> </deployment>
Note: As of alpha 2, when deploying Web services as a .jws
file, you should leave the service class in the default package, i.e., with no package declaration. On the other hand, when deploying services with a configuration file, as we did above, you should declare an explicit package -- for example, I've added a package javaworld.axis
declaration in HelloServer.java
. Following these guidelines will save you many headaches.
To deploy the service with a configuration file, follow these steps:
- Make sure that Tomcat is started.
- Create a
javaworld\axis
directory in theTOMCAT_HOME\webapps\axis\WEB-INF\classes\
directory. - Compile
HelloServer.java
and copy the resultingHelloServer.class
into the Axis directory created in Step 2. You don't need to set aCLASSPATH
to compileHelloServer.java
. -
Now execute the following commands:
set CLASSPATH=C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar;C:\xerces-1_4_4\xerces.jar java org.apache.axis.client.AdminClient deploy.xml
Here,
deploy.xml
is a file that contains the configuration XML shown above, not the WSDD form. If you want to test the newly deployed Web service, just change the following line in the client:String endpoint = "http://localhost:8080/axis/HelloServer.jws";
to:
String endpoint = "http://localhost:8080/axis/servlet/AxisServlet";
Also replace this line:
String ret = (String)client.invoke("","sayHelloTo",new Object [] {args[0]});
with:
String ret = (String)client.invoke("HelloServer","sayHelloTo",new Object[]{args[0]});
This time, instead of the endpoint being a
.jws
file, it is theAxisServlet
. The servlet locates and instantiates an instance of the class corresponding to the service nameHelloServer
and converts the SOAP messages into Java calls. The servlet then invokes the Java calls on the instantiated service class.
Abstract SOAP altogether
Most toolkits used for client-side Web services development are criticized because they require the client to have protocol-specific (e.g., SOAP-specific) knowledge. Overcoming this shortcoming has garnered much interest since Web services are protocol independent. IBM has been working on a toolkit called the Web Services Invocation Framework (WSIF), which abstracts all SOAP knowledge and instead works directly off the WSDL service description.
Similarly, in "Clean Up Your Wire Protocol with SOAP, Part 4," I created a class based on Java dynamic proxies that would abstract all SOAP details and make using SOAP-based services as intuitive as using any other Java class. Axis does that as well, but in a different way. Axis takes Apache SOAP one step further; it understands WSDL. WSDL is an XML-based language for describing Web services. You can use Axis to create a proxy (or stub) for your clients to abstract away SOAP and thus ease client-side development; it's simple. Just run the wsdl2java tool using the following commands from the directory that contains the javaworld.axis
package:
set CLASSPATH=C:\axis-1_0\lib\axis.jar; C:\axis-1_0\lib\log4j-core.jar;C:\xerces-1_4_4\xerces.jar; C:\axis-1_0\lib\wsdl4j.jar;C:\axis-1_0\lib\clutil.jar java org.apache.axis.wsdl.Wsdl2java -p javaworld.axis.proxy http://localhost:8080/axis/HelloServer.jws?wsdl
wsdl2java creates Java classes from a Web service's WSDL description. Axis automatically generates WSDL for any deployed service when you append ?wsdl
to the end of the service endpoint URL.
Now change the client as shown below:
package javaworld.axis; public class Client2 { public static void main(String[] args) throws Exception { javaworld.axis.proxy.HelloServer server = new javaworld.axis.proxy.HelloServer(); javaworld.axis.proxy.HelloServerPortType port = server.getHelloServerPort(); // make the call String ret = port.sayHelloTo(args[0]); System.out.println(ret); } }
Wow, that's neat! The client now interacts with the Web service in WSDL terms instead of SOAP terms. SOAP is completely abstracted away, and the client is now protocol neutral. You can try it by compiling the client as follows:
set CLASSPATH=C:\dev\;C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar; C:\xerces-1_4_4\xerces.jar;C:\axis-1_0\lib\wsdl4j.jar;C:\axis-1_0\lib\clutil.jar javac Client2.java
Then, run the client as shown here:
set CLASSPATH=C:\dev\;C:\axis-1_0\lib\axis.jar;C:\axis-1_0\lib\log4j-core.jar; C:\xerces-1_4_4\xerces.jar;C:\axis-1_0\lib\wsdl4j.jar;C:\axis- 1_0\lib\clutil.jar java javaworld.axis.Client2 John
Axis turns around Apache SOAP
In this article, I have only scratched the surface of Axis's new features. Remember, Axis is not just a rewrite of Apache SOAP; it is a complete re-architecture. It provides a SOAP toolkit that offers more than a library to abstract SOAP messages. Axis also has built-in support for WSDL and lets you create client-side proxies (or stubs) using Web services' WSDL definitions. With all its new features, Axis has truly taken Apache SOAP to the next level.
Tarak Modi, a senior specialist at North Highland, has been architecting scalable, high-performance, distributed applications for more than seven years. His professional experience includes hardcore C++ and Java programming; working with Microsoft technologies such as COM, MTS, and COM+; Java-based technologies including J2EE; and CORBA. He has a bachelor's degree in electrical engineering, a master's degree in computer engineering, and an MBA concentrating in information systems. Tarak is coauthor of the upcoming book, Professional Java Web Services, from Wrox. To learn more about Tarak, please visit his Website at http://tmodi.home.att.net/.Learn more about this topic
- Axis homepage
http://xml.apache.org/axis/index.html - Download the latest version of Tomcat
http://jakarta.apache.org/tomcat/index.html - Download Xerces for free
http://xml.apache.org/xerces2-j/index.html - "Clean Up Your Wire Protocol with SOAP," Tarak Modi (JavaWorld):
-
- Part 1. An introduction to SOAP basics (March 2001)
- Part 2. Use Apache SOAP to create SOAP-based applications (April 2001)
- Part 3. Create SOAP services in Apache SOAP with JavaScript (June 2001)
- Part 4. Dynamic proxies make Apache SOAP client development easy (July 2001)
- Find out more about WSDL
http://www.w3.org/TR/wsdl - Read more about the Chain of Responsibility design pattern in Design PatternsElements of Reusable Object-Oriented Software, Erich Gamma, et al. (Addison-Wesley, 1995; ISBN0201633612)
http://www.amazon.com/exec/obidos/ASIN/0201633612/javaworld - Summary of Apache/Microsoft Interoperability Meeting, March 12-14, 2001
http://xml.apache.org/axis/docs/ms-interop.html - To read more articles about Java and Web Services, browse our Topical Index
http://www.javaworld.com/channel_content/jw-webserv-index.shtml - Check out the inaugural article in JavaWorld's new Web Services column"A Birds-Eye View of Web Services," Frank Sommers (January 2002)
http://www.javaworld.com/javaworld/jw-01-2002/jw-0125-webservices.html - Speak out in our JavaWorld Forum
http://forums.idg.net/webx?13@@.ee6b802 - Sign up for JavaWorld's free weekly email newsletters
http://www.javaworld.com/jw-subscribe - You'll find a wealth of IT-related articles from our sister publications at IDG.net