Building .NET Web Service Clients using
Apache/SOAP and Java
In this example, we are going to
build an Apache/SOAP Java Client to the OIDServer
Web Service that we created earlier using C#/.NET. Since the
Apache SOAP Toolkit is designed as a Remote Procedure Call (RPC) mechanism as
opposed to a document exchange mechanism, it expects RPC encoding.
Therefore, the various steps that are
involved in creating a .NET Web Service Client using Apache/SOAP and Java are as
follows:
Develop a Class that generates the
SOAP message Body
element - the ApacheMessageBody.java
class file
Develop a Class that parses the
SOAP response - the SAXHandler.java
class file
Develop a Java Proxy for the .NET
endpoint - the ApacheSoapProxy.java
class file
Develop the Actual
Client - Client.java
class file
Build and Run
1. Develop a Class that generates
the SOAP message Body
element
Apache SOAP performs serialization
and deserialization using a class called
Body,
which uses its marshall()
and unmarshall()
methods to perform the respective operations.
While marshall()
is an instance method, unmarshall()
is a static class method. This means, it is
not possible to just inherit from the
Body class and override the
unmarshall()
method. However, you can change the Serialization
behavior of the Body
class by overriding the
marshall()
method as shown from Lines 30 through 51 in the
code below. Depending on the number of methods that you may have, you can either
create multiple Body
implementations, each with their own
marshall() methods,
or you may choose to build one Body
implementation with a single
marshall()method
which can choose the right code to execute based on other information.
Since ASP.NET endpoints use
document/literal encoding as opposed to RPC encoding, you
only need to write out the following information:
Write out the Body Element (as
shown on Lines 36-39 )
Write out the method name and
namespace information (as shown on Line 42 )
Write out the arguments that are
passed into the method (as shown on Lines 43 )
Notice that in the code below, we
extend the Body
class as shown on line 20
////////////////////////////////////////////////////// /// This Class generates the SOAP message Body element /// /// author:
Gopalan Suresh Raj /// Copyright (c), 2002. All Rights Reserved. /// URL:
https://gsraj.tripod.com/ /// email:
gopalan@gmx.net //////////////////////////////////////////////////////
/** * This Class generates the SOAP message Body element
* @author
Gopalan Suresh Raj */ public class ApacheMessageBody
extendsBody {
/** potential argument to the web method. */ //public String inputString_;
/** * Override the Apache default marshall method * and change how the SOAP Body element * is serialized. */ public void marshall (String inScopeEncodingStyle, Writer sink,
NSStack nameSpaceStack,
XMLJavaMappingRegistry registry,
SOAPContext context) throws IllegalArgumentException, IOException { // Set the Body element String soapEnvironmentNamespacePrefix = "SOAP-ENV"; sink.write ('<'+soapEnvironmentNamespacePrefix+':'+ Constants.ELEM_BODY+'>'+ StringUtils.lineSeparator);
// Write out the method name and related argument (s) sink.write ("<generateOID xmlns=\""http://tempuri.org/\">"+ //"<inputString>"+inputString_+"</inputString>"+ "</generateOID>");
// Close the Body element sink.write ("</" + soapEnvironmentNamespacePrefix+':'+ Constants.ELEM_BODY+'>'+ StringUtils.lineSeparator); nameSpaceStack.popScope (); } }
Now that you can send the message,
you should be able to read the message. To read the message, you need a class
that can handle SAX Processing for you and read the data.
2. Develop a Class that parses the SOAP Response
Whenever a message goes out and
comes back, the entire SOAP response can be determined. The
SAXHandler
class will be used by the Proxy that we will build soon. The SAX Response
Handler that we're building now is a general purpose class that can obtain any
single element response. Therefore, users should be able to use the class
without any other modifications. If the value is a Boolean, or other numeric, or
date types, you can perform the conversion after you retrieve the result using
the getResult() method
to obtain the single element response. You will be
required to modify the code for complex types and arrays.
/** * This Class parses the SOAP response. This is a * general purpose class that can obtain any single * element response. *
* @author
Gopalan Suresh Raj */ public class SAXHandler
extends DefaultHandler {
/** Default No argument constructor */ public SAXHandler () { }
/** * Retrieve the result for a single element * The code has to be modified as necessary * for more complex types and arrays */ public String getResult () { return result_; }
/** Provide the element name to search for */ public void setElementToSearchFor (String elementName) { elementToSearchFor_ = elementName; }
/** Retrieve the set element name */ public String getElementToSearchFor () { return elementToSearchFor_; }
/** * Overriden method of the DefaultHandler class to * gain notification of all SAX events */ public void startElement (String namespaceURI, String localName, String qName, Attributes attributes) throws SAXException { if (foundResult_ == false) { foundResult_ = (localName.compareTo (elementToSearchFor_) == 0); } }
/** * Overriden method of the DefaultHandler class to * gain notification of all SAX events */ public void characters (char[] characters, int start, int length) throws SAXException { if (foundResult_ == true) { result_ = String.valueOf (characters, start, length); foundResult_ = false; } }
}
3. Develop a Java Proxy for the .NET
Endpoint
Even though the IBM Web Services
toolkit can produce proxies, when it comes to .NET interoperability, it is
easier to build one by hand. The proxy will facilitate Client Applications to
instantiate the proxy and invoke method calls on the proxy, all the while only
worrying about handling SOAP faults. The proxy shown below performs the
following sets of operations:
Verifies that the URL set is
non-null
Constructs a Message
Sends over the Message
Parses the Response.
Since Apache SOAP 2.2 classes
encode messages using RPC encoding, for .NET interoperability which uses
document/literal encoding, you must override the code that constructs the body
in addition to the code that interprets the response.
////////////////////////////////////////////////////// /// This Class creates a Java Proxy for the .NET endpoint /// /// author:
Gopalan Suresh Raj /// Copyright (c), 2002. All Rights Reserved. /// URL:
https://gsraj.tripod.com/ /// email:
gopalan@gmx.net //////////////////////////////////////////////////////
/** * This Class creates a Java Proxy for the .NET endpoint
* @author
Gopalan Suresh Raj */ public class ApacheSoapProxy { private URL url_ = null; private String soapActionUri_ = ""; private Message message_ = new Message (); private Envelope envelope_ = new Envelope (); DataHandler soapMessage_ = null;
/** Default No argument constructor */ public ApacheSoapProxy () throws MalformedURLException { this.url_ = new URL ("http://localhost/OIDServer/OIDServer.asmx"); }
/** Set the End Point URL */ public synchronized void setEndPoint (URL url) { this.url_ = url; }
/** Retrieve the End Point URL */ public synchronized URL getEndPoint () { return this.url_; }
/** * Apache 2.2 classes encode messages differently than .NET does. * Therefore we have to override the piece that builds the body and * the pieces that interpret the response. */ public synchronized String generateOID () throws SOAPException { String returnValue = "";
if (this.url_ == null) { throw new SOAPException (Constants.FAULT_CODE_CLIENT, "A URL must be specified through "+ "ApacheSoapProxy.setEndPoint(URL)"); } // Get this from the soapAction attribute on the // soap:operation element that is found within the SOAP // binding information in the WSDL this.soapActionUri_ = "http://icommware.com/generateOID"; ApacheMessageBody ourBody = new ApacheMessageBody ();
// Set the argument //theBody.inputString_ = "";
// Replace the default body with our own this.envelope_.setBody (ourBody); message_.send (this.getEndPoint(), this.soapActionUri_, this.envelope_);
try { // Since the Body.unmarshall() handler is static, we can't // replace the basic machinery easily. Instead, we must obtain // and parse the message on our own. this.soapMessage_ = this.message_.receive(); XMLReader reader = (XMLReader)Class.forName("org.apache.xerces.parsers.SAXParser").newInstance(); SAXHandler handler = new SAXHandler(); handler.setElementToSearchFor ("generateOIDResult");
// Set the Content Handler reader.setContentHandler (handler);
// Parse the file reader.parse ( new InputSource (new StringReader (this.soapMessage_.getContent().toString() )));
// If we reached here, the result has been parsed and // stored in the handler instance. returnValue = handler.getResult (); } catch (Exception exception) { exception.printStackTrace (); } return returnValue; }
}
4. Develop the Actual Client
Notice that on Line 23, we
instantiate the Proxy, and on line 26, we call the web method on the proxy.
////////////////////////////////////////////////////// /// The following example illustrates a Client to a /// WebService developed using C# and the .NET Framework. /// /// author:
Gopalan Suresh Raj /// Copyright (c), 2002. All Rights Reserved. /// URL:
https://gsraj.tripod.com/ /// email:
gopalan@gmx.net //////////////////////////////////////////////////////
import java.io.*;
/** * Web Service Client Class
* @author
Gopalan Suresh Raj */ public class Client {
/** Entry Point to this Application */ public static void main(String[] args) { try { // Create a proxy ApacheSoapProxy proxy =
new ApacheSoapProxy ();
// Invoke generateOID() over SOAP and get the new OID String result =
proxy.generateOID ();
// Print out the value System.out.println ("The new OID is :"+result); } catch (java.net.MalformedURLException exception) { exception.printStackTrace (); } catch (org.apache.soap.SOAPException exception) { exception.printStackTrace (); } } }
C:\MyProjects\Cornucopia\WebService\javaSoapClient>java
-cp .;C:\java\xerces-1_4_3\xerces.jar;C:\java\soap-2_2\lib\soap.jar;C:\java\jaf-1.0.1\activation.
jar;C:\java\javamail-1.2\mail.jar;
Client
The new OID is :0d70d55a-b57e-4402-9e2e-1c51f20469b3