|
Development Guide |
This chapter walks you through the basic steps and a typical scenario for using the Web Service Wizard to generate a Web Service consumer (a program that accesses a Web Service). Topics include:
To learn about the steps and scenarios for using the wizard when you want to create a Web Service, see
Generating Web Services.
You can use the Web Service Wizard of Workbench to generate the code needed for a Java-based consumer program to access any standard (SOAP-based) Web Service. The generated code handles all HTTP SOAP processing under the covers, enabling the consumer program to call the Web Service as a Java remote object (using RMI) and invoke its methods.
For input, the wizard requires a WSDL file that describes the Web Service to access. It can handle a wide variety of Web Service implementations, including:
The wizard generates Java source files based on JAX-RPC (Java API for XML-based RPC) and jBroker Web (the JAX-RPC implementation included with Novell exteNd). JAX-RPC is the J2EE specification that provides Web Service support.
You can use the generated files as is or modify them when necessary. The advantage of this Java-oriented approach is that you can deal with Web Services using the familiar technologies of RMI and J2EE instead of coding lower-level SOAP APIs.
For an introduction to Web Service concepts, standards, and technologies, see
Understanding Web Services.
For detailed documentation on the wizard, see the Web Service Wizard chapter in the Tools Guide.
The process of developing your consumer program involves:
Preparing to generate by setting up your project
Providing a WSDL file that describes the Web Service for which you want the wizard to generate consumer code
Generating the consumer files by using the wizard
Examining the generated files that the wizard creates, including Java source for:
Editing the generated files to adjust the method calls to make and the Web Service location to point to
Using the generated files either as is or by including the consumer code in some other Java application
Running the consumer program in your development environment (for testing) and in the production environment
To prepare for using the Web Service Wizard, you:
Set up an appropriate project in Workbench.
The type of project you should create depends on how you ultimately plan to use the consumer code that the wizard will generate. For instance:
Add the archives required by jBroker Web to your project:
jbroker-web.jar, which contains the jBroker Web API classes needed at runtime
jaxrpc-api.jar and saaj-api.jar, which contain the Java API classes for XML-based RPC and SOAP processing
You'll find these JARs in the Workbench compilelib directory.
Edit the classpath of your project so you can compile your consumer classes once they're generated and edited. You'll need to include:
For J2EE projects, you'll also need j2ee_api_1_n.jar (it's included automatically when you create a J2EE project in Workbench).
If you use SOAP message handlers (an advanced JAX-RPC feature) in your application, the project will also require the following archives: activation.jar, commons-logging.jar, dom4j.jar, jaxp-api.jar, saaj-ri.jar, and j2ee_api_1_n.jar (for mail support). You'll find these JARs in the Workbench compilelib directory.
To generate consumer code, you'll need to provide the Web Service Wizard with a WSDL file that describes the target Web Service. It's a good idea to obtain the file location or URL of this WSDL file before you start the wizard.
For a Web Service developed in your organization, you might have the WSDL file on your file system or even in your project.
For an external Web Service, you should be able to get the WSDL file's URL from the appropriate Web site or registry.
Suppose you want to generate consumer code to use the Autoloan .NET Web Service, which is listed on the XMethods public registry under the name Equated Monthly Instalment (EMI) Calculator. That Web Service calculates and returns the monthly loan payment for a given term (number of months), interest rate, and loan amount.
In this case, you can go to the Web site www.xmethods.net to discover the URL for the corresponding WSDL file:
http://upload.eraserver.net/circle24/autoloan.asmx?wsdl
When you provide this URL to the Web Service Wizard, it will read the WSDL file to learn what it needs to know about the Autoloan Web Service:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="http://circle24.com/webservices/"
targetNamespace="http://circle24.com/webservices/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema attributeFormDefault="qualified" elementFormDefault="qualified"
targetNamespace="http://circle24.com/webservices/">
<s:element name="Calculate">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="Months" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="RateOfInterest" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="Amount" type="s:double" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="CalculateResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="CalculateResult" nillable="true"
type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="string" nillable="true" type="s:string" />
</s:schema>
</types>
<message name="CalculateSoapIn">
<part name="parameters" element="s0:Calculate" />
</message>
<message name="CalculateSoapOut">
<part name="parameters" element="s0:CalculateResponse" />
</message>
<message name="CalculateHttpGetIn">
<part name="Months" type="s:string" />
<part name="RateOfInterest" type="s:string" />
<part name="Amount" type="s:string" />
</message>
<message name="CalculateHttpGetOut">
<part name="Body" element="s0:string" />
</message>
<message name="CalculateHttpPostIn">
<part name="Months" type="s:string" />
<part name="RateOfInterest" type="s:string" />
<part name="Amount" type="s:string" />
</message>
<message name="CalculateHttpPostOut">
<part name="Body" element="s0:string" />
</message>
<portType name="AutoloanSoap">
<operation name="Calculate">
<input message="s0:CalculateSoapIn" />
<output message="s0:CalculateSoapOut" />
</operation>
</portType>
<portType name="AutoloanHttpGet">
<operation name="Calculate">
<input message="s0:CalculateHttpGetIn" />
<output message="s0:CalculateHttpGetOut" />
</operation>
</portType>
<portType name="AutoloanHttpPost">
<operation name="Calculate">
<input message="s0:CalculateHttpPostIn" />
<output message="s0:CalculateHttpPostOut" />
</operation>
</portType>
<binding name="AutoloanSoap" type="s0:AutoloanSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="Calculate">
<soap:operation soapAction="http://circle24.com/webservices/Calculate"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<binding name="AutoloanHttpGet" type="s0:AutoloanHttpGet">
<http:binding verb="GET" />
<operation name="Calculate">
<http:operation location="/Calculate" />
<input>
<http:urlEncoded />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<binding name="AutoloanHttpPost" type="s0:AutoloanHttpPost">
<http:binding verb="POST" />
<operation name="Calculate">
<http:operation location="/Calculate" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<service name="Autoloan">
<documentation>This Web Service mimics a Simple Autoloan calculator.</documentation>
<port name="AutoloanSoap" binding="s0:AutoloanSoap">
<soap:address location="http://upload.eraserver.net/circle24/autoloan.asmx" />
</port>
<port name="AutoloanHttpGet" binding="s0:AutoloanHttpGet">
<http:address location="http://upload.eraserver.net/circle24/autoloan.asmx" />
</port>
<port name="AutoloanHttpPost" binding="s0:AutoloanHttpPost">
<http:address location="http://upload.eraserver.net/circle24/autoloan.asmx" />
</port>
</service>
</definitions>
In the Autoloan WSDL, you can ignore the definitions for HttpGet and HttpPost (including message, portType, binding, and service port). Only the Soap definitions apply to the Web Service consumer program you're developing.
Notice that this Web Service exposes one method named calculate(). It takes a Calculate object containing three doubles (Months, RateOfInterest, and Amount) and returns a CalculateResponse object containing one string (CalculateResult). The Web Service Wizard will generate a corresponding remote interface in Java to support calling this method.
The types section specifies the XML Schema definitions for Calculate and CalculateResponse. The Web Service Wizard will generate corresponding type classes in Java to represent these objects.
If you look in the binding section for AutoloanSoap, you'll see that this Web Service is defined as document style (as opposed to RPC style). That's typical of .NET Web Services. Binding style describes the format of SOAP messages and can affect interoperability with other Web Service environments:
The Web Service Wizard will generate the Java code needed to handle the specified binding style.
The port definition for AutoloanSoap (at the end of the WSDL file) specifies the address (URL) where the Web Service can be accessed:
http://upload.eraserver.net/circle24/autoloan.asmx
The Web Service Wizard will use this URL in the service and stub classes it generates for calling the Web Service.
Once you've set up your project and located the appropriate WSDL file, you're ready to use the Web Service Wizard. The wizard produces one Web Service consumer at a time, so you'll need to use it multiple times if you have several to develop.
Each time you launch the wizard, it uses the WSDL file and other input you provide to generate a set of consumer source files. Here's a summary of the process:
Select File>New to display the New File dialog and go to the Web Services tab.
Launch the Web Service Wizard by selecting Existing Web Service.
When the wizard prompts you for project location information, specify:
For example, suppose you're generating a consumer for the Autoloan Web Service. You might specify WebServiceConsumerSample as the target JAR project and com.exsamp.net as the package for generated classes:
When the wizard prompts you, specify the WSDL file that describes your target Web Service.
For example, when generating a consumer for the Autoloan Web Service, you specify the WSDL file URL obtained from the XMethods public registry:
When the wizard prompts you for class-generation and SOAP options, you must specify details about the code to create:
To get the files needed for a Web Service consumer, check Generate stubs (and leave Generate skeletons unchecked).
To automatically generate type classes for any complex types in the WSDL, check Map complex XML types to Java types.
For example, these options will generate the appropriate consumer source files (including type classes) for the Autoloan Web Service:
NOTE: Support for jBroker Web 1.x applications is available via a backward-compatibility option. For more information, see If you choose jBroker Web 1.x compatibility (in the preceding chapter).
Click Finish when you're done specifying options for the Web Service consumer.
Once you finish the wizard, it generates everything you've specified for your Web Service consumer and updates other parts of your project with supporting changes:
When generating file names, the Web Service Wizard follows the naming rules specified by JAX-RPC. For a Web Service consumer, the resulting file names are based on the definitions in the WSDL.
For simplicity, this documentation uses xxx to represent the portion of a generated Web Service consumer file name that's derived from a WSDL definition.
Under the covers, the Web Service Wizard uses the jBroker Web compilers when generating the Web Service consumer files listed above. In some cases, these compilers may generate additional code or files to support requirements specific to your application, such as:
For more information, see the jBroker Web help.
The consumer code that the Web Service Wizard generates for the Autoloan Web Service consists of these standard files for Web Service access:
AutoloanSoap.java (remote interface)
Autoloan.java (service interface)
AutoloanImpl.java (service implementation class)
And these application-specific files for mapping the complex types defined in the WSDL:
When creating these files, the wizard adds them to your project on the directory path you've specified:
This is the remote interface used by the stub class to support method calls for the Autoloan Web Service.
package com.exsamp.net;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface AutoloanSoap extends Remote
{
com.exsamp.net.CalculateResponse calculate(com.exsamp.net.Calculate parameters)
throws RemoteException;
}
This is the service interface that's used in JAX-RPC to help clients obtain the stub for the Web Service.
package com.exsamp.net;
import javax.xml.rpc.ServiceException;
public interface Autoloan extends javax.xml.rpc.Service
{
public AutoloanSoap_Stub getAutoloanSoap()
throws ServiceException;
}
This is the service implementation class that handles instantiation of the stub (AutoloanSoap_Stub).
package com.exsamp.net;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.Properties;
import java.util.ArrayList;
import java.net.URL;
import java.net.MalformedURLException;
import javax.xml.rpc.Call;
import javax.xml.rpc.ParameterMode;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceException;
import com.sssw.jbroker.web.Binding;
import com.sssw.jbroker.web.encoding.DefaultTypeMappingRegistry;
public class AutoloanImpl
extends com.sssw.jbroker.web.xml.rpc.ServiceImpl
implements Autoloan
{
public AutoloanImpl()
{
try {
_typeMappingRegistry.importTypeMappings(_tmprops);
} catch (Exception ex) {
throw new javax.xml.rpc.JAXRPCException("failed to populate default type mapping registry: " + ex.getMessage());
}
try {
createCalls();
} catch (ServiceException ex) {
throw new javax.xml.rpc.JAXRPCException("failed to create the call objects: " + ex.getMessage());
}
}
public QName getServiceName() { return _serviceName; }
public Iterator getPorts() { return _portMapping.keySet().iterator(); }
public void setProxyMode(boolean proxy) { _proxy = proxy; }
public boolean getProxyMode() { return _proxy; }
public URL getWSDLDocumentLocation()
{
return null;
}
public java.rmi.Remote getPort(Class serviceDefInterface)
throws ServiceException
{
if (serviceDefInterface == null)
throw new ServiceException("No Service class specified.");
if (!java.rmi.Remote.class.isAssignableFrom(serviceDefInterface))
throw new ServiceException("Class is not a valid Interface.");
String stubName = (String) _intfMapping.get(serviceDefInterface);
Binding binding = (Binding) _intfBinding.get(serviceDefInterface);
if (stubName == null)
return getPort(serviceDefInterface, binding,
_classInfo, _typeMappingRegistry, null);
else
return getPort(stubName, binding, _typeMappingRegistry);
}
public java.rmi.Remote getPort(QName portName, Class serviceDefInterface)
throws ServiceException
{
return getPort(portName, serviceDefInterface, getProxyMode());
}
public java.rmi.Remote getPort(QName portName, Class serviceDefInterface, boolean proxy)
throws ServiceException
{
if (((proxy==false) || (serviceDefInterface == null)) &&
(portName != null)) {
String stubName = (String) _portMapping.get(portName);
Binding binding = (Binding) _portBinding.get(portName);
if (stubName == null) return getPort(null, serviceDefInterface);
try {
return getPort(stubName, binding, portName,
_typeMappingRegistry);
} catch (Exception ex) {
return getPort(null, serviceDefInterface);
}
} else {
if (serviceDefInterface == null)
throw new ServiceException("No Service class specified.");
if (!java.rmi.Remote.class.isAssignableFrom(serviceDefInterface))
throw new ServiceException("Class is not a valid Interface.");
Binding binding = (Binding) _intfBinding.get(serviceDefInterface);
String uri = (portName == null) ? null : portName.getNamespaceURI();
return getPort(serviceDefInterface, binding, _classInfo,
_typeMappingRegistry, uri);
}
}
public Call[] getCalls(QName portName)
throws ServiceException
{
ArrayList callslist = (ArrayList) _calls.get(portName);
if (callslist == null) return null;
Call[] calls = new Call[callslist.size()];
return (Call[]) callslist.toArray(calls);
}
private void addCall(QName portName, Call call)
{
ArrayList callslist = (ArrayList) _calls.get(portName);
if (callslist == null) {
callslist = new ArrayList();
_calls.put(portName, callslist);
}
callslist.add(call);
}
public AutoloanSoap_Stub getAutoloanSoap()
throws ServiceException
{
try {
return (AutoloanSoap_Stub) getPort(new QName(
"http://circle24.com/webservices/", "AutoloanSoap"), null, false);
} catch (Exception ex) {
return (AutoloanSoap_Stub) getPort(com.exsamp.net.AutoloanSoap.class);
}
}
private void createCalls()
throws ServiceException
{
Call call = null;
call = createCall(new QName("http://circle24.com/webservices/", "AutoloanSoap"),
new QName("http://circle24.com/webservices/", "Calculate"));
call.addParameter("{http://circle24.com/webservices/}Calculate",
new QName("http://circle24.com/webservices/", "Calculate"), com.exsamp.net.Calculate.class, ParameterMode.IN);
call.addParameter("{http://circle24.com/webservices/}CalculateResponse",
new QName("http://circle24.com/webservices/", "CalculateResponse"), com.exsamp.net.CalculateResponse.class, ParameterMode.OUT);
call.setReturnType(new QName("http://circle24.com/webservices/", "CalculateResponse"), com.exsamp.net.CalculateResponse.class);
call.setProperty(Call.OPERATION_STYLE_PROPERTY, "document");
call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY, null);
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "\"http://circle24.com/webservices/Calculate\"");
call.setTargetEndpointAddress("http://upload.eraserver.net/circle24/autoloan.asmx");
addCall(new QName("http://circle24.com/webservices/", "AutoloanSoap"), call);
}
static boolean _proxy = true;
static final QName _serviceName;
static final Hashtable _intfMapping = new Hashtable();
static final Hashtable _intfBinding = new Hashtable();
static final Hashtable _portBinding = new Hashtable();
static final Hashtable _portMapping = new Hashtable();
static final Hashtable _classInfo = new Hashtable();
static final Properties _tmprops = new Properties();
private final Hashtable _calls = new Hashtable();
static {
_serviceName = new QName("http://circle24.com/webservices/", "com.exsamp.net.Autoloan");
_intfBinding.put(AutoloanSoap.class,
new Binding("soap", "http://upload.eraserver.net/circle24/autoloan.asmx"));
_portBinding.put(new QName("http://circle24.com/webservices/", "AutoloanSoap"),
new Binding("soap", "http://upload.eraserver.net/circle24/autoloan.asmx"));
_intfMapping.put(AutoloanSoap.class, "com.exsamp.net.AutoloanSoap_Stub");
_portMapping.put(new QName("http://circle24.com/webservices/",
"AutoloanSoap"), "com.exsamp.net.AutoloanSoap_Stub");
Hashtable _methodInfo;
Hashtable _paramInfo;
Properties _props;
_methodInfo = new Hashtable();
_paramInfo = new Hashtable();
_props = new Properties();
_props.setProperty("jbroker.web.soap.action","\"http://circle24.com/webservices/Calculate\"");
_paramInfo.put("Properties", _props);
_props = new Properties();
_props.setProperty("jbroker.web.parameter.name", "parameters");
_props.setProperty("jbroker.web.parameter.inout", "1");
_paramInfo.put("Param0", _props);
_props = new Properties();
_props.setProperty("jbroker.web.parameter.name", "parameters");
_props.setProperty("jbroker.web.parameter.inout", "2");
_paramInfo.put("Result", _props);
_methodInfo.put("Calculate", _paramInfo);
_classInfo.put("com.exsamp.net.AutoloanSoap", _methodInfo);
_tmprops.put("tm1", "com.exsamp.net.CalculateResponse com.exsamp.net.CalculateResponseMarshaler com.exsamp.net.CalculateResponseMarshaler http://circle24.com/webservices/ CalculateResponse none");
_tmprops.put("tm0", "com.exsamp.net.Calculate com.exsamp.net.CalculateMarshaler com.exsamp.net.CalculateMarshaler http://circle24.com/webservices/ Calculate none");
}
}
This is the stub class. It passes method calls to the Autoloan Web Service as HTTP SOAP requests.
package com.exsamp.net;
import com.exsamp.net.holders.*;
import java.util.Properties;
import com.sssw.jbroker.web.core.Constants;
import com.sssw.jbroker.web.encoding.TypeMappingRegistry;
import com.sssw.jbroker.web.encoding.DefaultTypeMappingRegistry;
public class AutoloanSoap_Stub
extends com.sssw.jbroker.web.portable.Stub
implements AutoloanSoap
{
private static com.sssw.jbroker.web.QName _portType =
new com.sssw.jbroker.web.QName("http://circle24.com/webservices/", "AutoloanSoap");
private static final com.sssw.jbroker.web.Binding[] _bindings =
new com.sssw.jbroker.web.Binding[] {
new com.sssw.jbroker.web.Binding("soap", "http://upload.eraserver.net/circle24/autoloan.asmx"),
};
public AutoloanSoap_Stub()
{
this(null);
}
public AutoloanSoap_Stub(DefaultTypeMappingRegistry tmr)
{
super(_portType, _bindings);
_setProperty("xmlrpc.schema.uri", (Object) "http://www.w3.org/2001/XMLSchema".intern());
_setProperty("version", (Object) "1.1");
TypeMappingRegistry _tm = null;
try {
if (tmr != null)
_tm = tmr;
else {
_tm = new DefaultTypeMappingRegistry();
if (_tmprops.size() > 0) _tm.importTypeMappings(_tmprops);
}
_setTypeMappingRegistry(_tm);
} catch (Exception ex) {
throw new javax.xml.rpc.JAXRPCException("failed to initialize type mapping registry: " + ex.getMessage());
}
}
public com.exsamp.net.CalculateResponse calculate(com.exsamp.net.Calculate _arg0)
throws java.rmi.RemoteException
{
com.sssw.jbroker.web.portable.ClientResponse in = null;
try {
// create an output stream
_getDelegate().setProperty("xmlrpc.soap.operation.name",
new com.sssw.jbroker.web.QName("http://circle24.com/webservices/", "Calculate"));
//create request
com.sssw.jbroker.web.portable.ClientRequest out =
_request("Calculate", true, "literal", true, "\"http://circle24.com/webservices/Calculate\"");
_getDelegate().setProperty("soapAction", (Object) "\"http://circle24.com/webservices/Calculate\"");
_getDelegate().setProperty(Constants.HTTP_CONTENT_TYPE, (Object) "text/xml; charset=utf-8");
out._setProperties(_getDelegate().getProperties());
Object arg = null;
// marshal the parameters
arg = _arg0;
out.writeObject(arg, "http://circle24.com/webservices/", "Calculate");
// do the invocation
in = _invoke(out);
// unmarshal the results
// return
com.exsamp.net.CalculateResponse ret = null;
try {
ret = (com.exsamp.net.CalculateResponse)
in.readObject(com.exsamp.net.CalculateResponse.class, "http://circle24.com/webservices/", "CalculateResponse");
} catch (java.io.EOFException eofExc) {
ret = null;
}
return ret;
} catch (java.lang.Throwable t) {
if (t instanceof com.sssw.jbroker.web.ServiceException) {
com.sssw.jbroker.web.ServiceException sex =
(com.sssw.jbroker.web.ServiceException) t;
if (sex.getTargetException() != null)
t = sex.getTargetException();
}
// map to remote exception
throw com.sssw.jbroker.web.ServiceException.mapToRemote(t);
}
}
static final Properties _tmprops = new Properties();
static {
_tmprops.put("tm1", "com.exsamp.net.CalculateResponse com.exsamp.net.CalculateResponseMarshaler com.exsamp.net.CalculateResponseMarshaler http://circle24.com/webservices/ CalculateResponse none");
_tmprops.put("tm0", "com.exsamp.net.Calculate com.exsamp.net.CalculateMarshaler com.exsamp.net.CalculateMarshaler http://circle24.com/webservices/ Calculate none");
}
private static Properties _rootHeaders = new Properties();
static {
_rootHeaders.setProperty("content-type", "text/xml; charset=UTF-8");
_rootHeaders.setProperty("content-id", "<soapbody>");
}
}
This is a simple client application that obtains the stub (via the Service object) and then uses it to call the calculate() method of the Autoloan Web Service. (Notice that this method call is generated as a comment. You'll learn what to do with it a little later, in Editing the generated files.)
package com.exsamp.net;
import javax.naming.*;
public class AutoloanSoapClient
{
public void process(String[] args) throws Exception
{
AutoloanSoap remote = getRemote(args);
// The following code has been generated for your testing convenience. In
// order to successfully test your Web Service, you must uncomment one or
// more of these lines and supply meaningful arguments where necessary.
// Once you have modified the test method(s) below, compile this class and
// execute it from a command line with your class path set appropriately.
// System.out.println("Test Result = " + remote.calculate(com.exsamp.net.Calculate));
}
public AutoloanSoap getRemote(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
String lookup = "xmlrpc:soap:com.exsamp.net.Autoloan";
Autoloan service = (Autoloan)ctx.lookup(lookup);
AutoloanSoap remote = (AutoloanSoap)service.getAutoloanSoap();
return remote;
}
public static void main(String[] args)
{
try
{
AutoloanSoapClient client = new AutoloanSoapClient();
client.process(args);
}
catch (Exception _e)
{
System.out.println("*** Error Executing Generated Test Client ***");
_e.printStackTrace();
}
}
}
This class represents the complex type Calculate that's defined in the WSDL.
package com.exsamp.net;
public class Calculate implements java.io.Serializable
{
public Calculate() {}
public Calculate(double monthsVal, double rateOfInterestVal, double amountVal) {
_months = monthsVal;
_rateOfInterest = rateOfInterestVal;
_amount = amountVal;
}
private double _months;
public double getMonths() {
return _months;
}
public void setMonths(double monthsVal) {
_months = monthsVal;
}
private double _rateOfInterest;
public double getRateOfInterest() {
return _rateOfInterest;
}
public void setRateOfInterest(double rateOfInterestVal) {
_rateOfInterest = rateOfInterestVal;
}
private double _amount;
public double getAmount() {
return _amount;
}
public void setAmount(double amountVal) {
_amount = amountVal;
}
public java.lang.String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("{");
buffer.append("months=" + _months);
buffer.append(",");
buffer.append("rateOfInterest=" + _rateOfInterest);
buffer.append(",");
buffer.append("amount=" + _amount);
buffer.append("}");
return buffer.toString();
}
}
This class handles serialization and deserialization for Calculate.
package com.exsamp.net;
import java.io.IOException;
import org.xml.sax.Attributes;
import com.sssw.jbroker.web.*;
import com.sssw.jbroker.web.encoding.*;
import com.sssw.jbroker.web.portable.InputStream;
import com.sssw.jbroker.web.portable.OutputStream;
public class CalculateMarshaler implements Marshaler
{
// attributes
// elements
private static final java.lang.String _MONTHS = "Months";
private static final java.lang.String _RATEOFINTEREST = "RateOfInterest";
private static final java.lang.String _AMOUNT = "Amount";
public Attribute[] getAttributes(Object obj)
{
return null;
}
public void serialize(OutputStream os, Object obj) throws IOException
{
Calculate jt = (Calculate) obj;
os.writeObject(new java.lang.Double(jt.getMonths()), _MONTHS);
os.writeObject(new java.lang.Double(jt.getRateOfInterest()), _RATEOFINTEREST);
os.writeObject(new java.lang.Double(jt.getAmount()), _AMOUNT);
}
public Object deserialize(InputStream is, Class javaType)
throws IOException
{
if (javaType != Calculate.class)
throw new
ServiceException("can't deserialize " + javaType.getName());
try {
// instantiate the object
Calculate jt = (Calculate) javaType.newInstance();
try {
// read elements
jt.setMonths(is.readDouble(_MONTHS));
jt.setRateOfInterest(is.readDouble(_RATEOFINTEREST));
jt.setAmount(is.readDouble(_AMOUNT));
} catch (java.io.EOFException eofExc) {}
return jt;
} catch (Exception ex) {
if (ex instanceof IOException)
throw (IOException) ex;
throw new ServiceException(ex);
}
}
public java.lang.String getMechanismType() { return null; }
}
This is the Holder class required by JAX-RPC to implement type mapping support for Calculate. Note that this class is generated in the holders subdirectory.
package com.exsamp.net.holders;
import com.exsamp.net.Calculate;
public final class CalculateHolder implements javax.xml.rpc.holders.Holder
{
public com.exsamp.net.Calculate value;
public CalculateHolder() { }
public CalculateHolder(com.exsamp.net.Calculate val)
{
value = val;
}
}
This class represents the complex type CalculateResponse that's defined in the WSDL.
package com.exsamp.net;
public class CalculateResponse implements java.io.Serializable
{
public CalculateResponse() {}
public CalculateResponse(java.lang.String calculateResultVal) {
_calculateResult = calculateResultVal;
}
private java.lang.String _calculateResult;
public java.lang.String getCalculateResult() {
return _calculateResult;
}
public void setCalculateResult(java.lang.String calculateResultVal) {
_calculateResult = calculateResultVal;
}
public java.lang.String toString()
{
StringBuffer buffer = new StringBuffer();
buffer.append("{");
buffer.append("calculateResult=" + _calculateResult);
buffer.append("}");
return buffer.toString();
}
}
This class handles serialization and deserialization for CalculateResponse.
package com.exsamp.net;
import java.io.IOException;
import org.xml.sax.Attributes;
import com.sssw.jbroker.web.*;
import com.sssw.jbroker.web.encoding.*;
import com.sssw.jbroker.web.portable.InputStream;
import com.sssw.jbroker.web.portable.OutputStream;
public class CalculateResponseMarshaler implements Marshaler
{
// attributes
// elements
private static final java.lang.String _CALCULATERESULT = "CalculateResult";
public Attribute[] getAttributes(Object obj)
{
return null;
}
public void serialize(OutputStream os, Object obj) throws IOException
{
CalculateResponse jt = (CalculateResponse) obj;
os.writeObject(jt.getCalculateResult(), _CALCULATERESULT);
}
public Object deserialize(InputStream is, Class javaType)
throws IOException
{
if (javaType != CalculateResponse.class)
throw new
ServiceException("can't deserialize " + javaType.getName());
try {
// instantiate the object
CalculateResponse jt = (CalculateResponse) javaType.newInstance();
try {
// read elements
jt.setCalculateResult((java.lang.String)is.readObject(java.lang.String.class, _CALCULATERESULT));
} catch (java.io.EOFException eofExc) {}
return jt;
} catch (Exception ex) {
if (ex instanceof IOException)
throw (IOException) ex;
throw new ServiceException(ex);
}
}
public java.lang.String getMechanismType() { return null; }
}
This is the Holder class required by JAX-RPC to implement type mapping support for CalculateResponse. Note that this class is generated in the holders subdirectory.
package com.exsamp.net.holders;
import com.exsamp.net.CalculateResponse;
public final class CalculateResponseHolder implements javax.xml.rpc.holders.Holder
{
public com.exsamp.net.CalculateResponse value;
public CalculateResponseHolder() { }
public CalculateResponseHolder(com.exsamp.net.CalculateResponse val)
{
value = val;
}
}
The settings specified in this file tell jBroker Web how to configure the type mappings for Calculate and CalculateResponse. These mappings apply when data is converted from XML to Java or vice versa.
Since the generated stub and service classes automatically configure the mappings, this mappings file is not typically needed. It is provided for special situations (such as when you want to override a mapping).
The mappings file is generated in the base directory of the source tree (src).
Calculate=com.exsamp.net.Calculate com.exsamp.net.CalculateMarshaler com.exsamp.net.CalculateMarshaler http://circle24.com/webservices/ Calculate none CalculateResponse=com.exsamp.net.CalculateResponse com.exsamp.net.CalculateResponseMarshaler com.exsamp.net.CalculateResponseMarshaler http://circle24.com/webservices/ CalculateResponse none
Follow these guidelines when editing the files generated by the Web Service Wizard:
|
Guideline |
Details |
|---|---|
|
File you must edit |
|
|
Files you should not edit |
It's OK to edit any of the other generated files, but not typically required.
Before using the generated xxxClient.java file, you:
Must edit the process() method to call one or more methods of the target Web Service
May need to edit the getRemote() method to specify the correct location (binding) for accessing the target Web Service
The process() method is where the generated client application calls methods of the Web Service. Here you'll find commented code for calling each method defined in the generated remote interface and displaying return values on the console. For example:
public void process(String[] args) throws Exception
{
AutoloanSoap remote = getRemote(args);
// The following code has been generated for your testing convenience. In
// order to successfully test your Web Service, you must uncomment one or
// more of these lines and supply meaningful arguments where necessary.
// Once you have modified the test method(s) below, compile this class and
// execute it from a command line with your class path set appropriately.
// System.out.println("Test Result = " + remote.calculate(com.exsamp.net.Calculate));
}
You need to modify this code as follows:
Provide appropriate arguments for each method call, either as hardcoded values or as parameters to be furnished at runtime. For runtime arguments, you may also want to add code that validates the values supplied.
Check the return data type to make sure it can be converted using toString(). If not, use an alternative to System.out.println for displaying the data returned.
Here's what the line with the calculate() method call looks like after editing:
System.out.println("Autoloan Web Service\n " +
"Loan input data:\n 24 months, 8%, $15000\n " +
"Output from the Web Service:\n " +
remote.calculate(new com.exsamp.net.Calculate(24, 8, 15000)));
This section explains the basic use of the getRemote() method and how to modify it when you need to specify binding information.
Basic use The getRemote() method is where the generated client application obtains the remote object to handle its method calls to the Web Service. That remote object is an instance of the generated stub class (xxx_Stub). To create the stub instance, getRemote() does the following:
Instantiates the Service object (from the service interface and implementation classes, xxxService and xxxServiceImpl) via JNDI lookup
Calls a method that the Service object provides (in the service interface) to get the stub
Here's an example of the typical code generated for getRemote(). Normally, you don't need to edit it:
public AutoloanSoap getRemote(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
String lookup = "xmlrpc:soap:com.exsamp.net.Autoloan";
Autoloan service = (Autoloan)ctx.lookup(lookup);
AutoloanSoap remote = (AutoloanSoap)service.getAutoloanSoap();
return remote;
}
Specifying binding information The wizard includes the binding information for your target Web Service in the generated stub class (xxx_Stub.java) and service implementation class (xxxServiceImpl.java). The binding provides the service endpoint address where the Web Service can be accessed. In a WSDL file, this address is the URL in the soap:address location element.
As an alternative, you can specify the binding to use when creating the stub instance in the getRemote() method. This enables you to override the binding in the stub class (such as when the Web Service has moved to a new location). You just need to add a line of code to set the address property for the stub:
public AutoloanSoap getRemote(String[] args) throws Exception
{
InitialContext ctx = new InitialContext();
String lookup = "xmlrpc:soap:com.exsamp.net.Autoloan";
Autoloan service = (Autoloan)ctx.lookup(lookup);
AutoloanSoap remote = (AutoloanSoap)service.getAutoloanSoap();
((javax.xml.rpc.Stub)remote)._setProperty("javax.xml.rpc.service.endpoint.address",
"http://upload.eraserver.net/circle24/autoloan.asmx");
return remote;
}
How you use the Web Service consumer code that you have at this point depends on the nature of the application you're developing. Sometimes you might want to enhance the generated xxxClient.java file and include it in your application. At other times you may just copy syntax from xxxClient.java into your own classes. But in either case, you'll always need the generated remote interface, service, and stub files.
Before you start any application-specific coding, it's a good idea to test the basic xxxClient to make sure your consumer code works as expected. You'll first need to build your project to compile the source files. Then you can run xxxClient, as described in the next section.
The generated Web Service consumer program xxxClient is a standard Java application. You can run it in either of these ways:
To help you test your generated client quickly and easily, Workbench provides the Web Service Wizard Client Runner. This facility lists the client applications in your current project and lets you select one to execute. For each run, it automatically sets the classpath to include all required files and lets you supply command-line arguments.
Open the project that contains the compiled client class you want to run.
Select Project>Run Web Service Client Class to display the Client Runner window.
Select a client from the Client class to run dropdown.
This dropdown lists every compiled class in your project that has a main() method.
Type any command-line Arguments required by your client (use a space to separate each argument).
Click Run to execute your client and see its output in the display console portion of the window.
For example, here's what it looks like to execute the generated AutoloanSoapClient class using the Client Runner:
When AutoloanSoapClient runs, it calls the calculate() method of the Autoloan Web Service and passes a Calculate object containing loan data (term, rate, amount). The calculate() method returns a CalculateResponse object containing a string of payment information, which AutoloanSoapClient displays on the screen:
Running com.exsamp.net.AutoloanSoapClient...
*********************
Autoloan Web Service
Loan input data:
24 months, 8%, $15000
Output from the Web Service:
{calculateResult=Equated Monthly Instalment (EMI) For the Amount $15000 is $678}
*********************
You can also execute the generated client from the command prompt of your operating system. Doing so demands that you set the classpath to include all required files (such as the generated consumer classes, jbroker-web.jar, and so on).
The recommended approach is to use the Web Service Wizard Client Runner to display and copy the command line for your client (as described in the preceding section). Then you can paste that line to your command prompt and run it.
If you plan to run the client on other computers (beyond your development machine), make sure they have access to all of the files listed in this command line.
|
Development Guide |
Copyright © 2001, 2002, 2003 SilverStream Software, LLC, a wholly owned subsidiary of Novell, Inc. All rights reserved.