Sun Java Solaris Communities My SDN Account Join SDN
 
Article

The Java Web Services Developer Pack, Part 2

 
 

What's This About? | XML Technologies for RPC Calls and Messaging | JAXM | Build and Run the Sample Application

Web Services Developer Pack

JAX-RPC

JAXR-RPC is a Java API for making RPC calls that conform to SOAP specifications.

JAX-RPC is a Java API for accessing Web services through XML (SOAP-based) RPC calls. It allows a Java-based client to call Web service methods in a distributed environment, for example, where the client and the Web service are on different systems. From an application developer's point of view, JAX-RPC provides a way to call a Web service. From a Web service developer's point of view, it provides a way to make a Web service available so that it can be called from an application.

Although JAX-RPC is a Java API, it doesn't limit the client and the Web service to both be deployed on a Java platform. A Java-based client can use JAX-RPC to make SOAP-based RPC calls to Web service methods on a non-Java platform. A client on a non-Java platform can access methods in a JAX-RPC enabled Web service on a Java platform.

Also, though JAX-RPC offers a way to make SOAP-based RPC calls, it's designed to hide the complexity of SOAP. When you use JAX-RPC to make an RPC call, you don't explicitly code a SOAP message. Instead you code the call in the Java programming language, using the Java API. JAX-RPC converts the RPC call to a SOAP message and then transports the SOAP message to the server. The server converts the SOAP message and then processes it. Then the sequence is reversed. The server converts the response to a SOAP message and transports it back to the client.

In order to understand and use JAX-RPC, it's important to understand some basic concepts. These concepts include:

After you're familiar with these concepts, see the JAX-RPC Example.

Service Endpoints

JAX-RPC relies on WSDL for a description of Web services. WSDL describes a Web service as a collection of ports, also called endpoints, that operate on messages. Each of these endpoints identifies the distinct actions provided by the Web service, and the data passed to each action. In JAX-RPC, requests are directed to endpoints.

In JAX-RPC, requests are directed to endpoints. To make a Web service available to clients through JAX-RPC, a Web service developer needs to provide a JAX-RPC service endpoint definition.

JAX-RPC's reliance on WSDL is important for interoperability. WSDL defines an XML schema for describing a Web service, not a Java schema. Because JAX-RPC doesn't limit the client and the Web service to both be on a Java platform, it needs a way for a Web service to be defined such that the definition is recognized on multiple platforms. WSDL provides for this platform-independent definition.

To make a Web service available to clients through JAX-RPC, a Web service developer needs to provide a JAX-RPC service endpoint definition. This involves defining two Java classes for each endpoint: one that defines the JAX-RPC service endpoint interface, and the other that implements the interface. At this point you might ask "what about a Web service that's not on a Java platform?" For these services, a Web service developer can use a mapping tool to generate the JAX-RPC service endpoint definition from a WSDL document. See Java-WSDL/XML Mappings for more details.

The service endpoint interface describes the remote interface to the client. In other words, it identifies the remote methods that can be called by the client and the method signatures. The implementation class provides the code to be executed for each method. Here, for example, is a Java class that defines a service endpoint interface, StockQuoteProvider, for a stock quote service. Only one method is defined in the interface: getLastTradeprice. The method takes as input a string that represents a ticker symbol, tickerSymbol, and returns a float value (the last traded price for the stock represented by the ticker symbol).

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface StockQuoteProvider extends Remote {

public float getLastTradePrice(String tickerSymbol) 
                                throws RemoteException;
}

All JAX-RPC service endpoint definitions must extend the java.rmi.Remote interface, and their methods must declare that they throw a java.rmi.RemoteException exception.

Notice that the service endpoint definition extends the java.rmi.Remote interface, and the method declares that it throws a java.rmi.RemoteException exception. These are JAX-RPC requirements. All JAX-RPC service endpoint definitions must extend the java.rmi.Remote interface, and their methods must declare that they throw a java.rmi.RemoteException exception. There are other rules that govern JAX-RPC service endpoint interfaces. For example, method parameters and return types must be JAX-RPC supported types.

The service developer would then need to provide the implementation class for the getLastTradePrice method. It would look something like this:

import java.xml.rpc.server.ServiceLifecycle;

public class StockQuoteService implements 
               StockQuoteProvider, ServiceLifecycle {

public float getLastTradePrice(String tickerSymbol)
    {   
      // Code for the method 
	  ...
    }   
	
}

Notice that the class implements the ServiceLifecycle interface as well as the StockQuoteProvider interface. The JAX-RPC runtime system uses the implementation of the ServiceLifecycle interface to manage the lifecycle of the service endpoint class. For example, the runtime system uses the implementation of methods in the ServiceLifecycle interface to initialize and eliminate instances of the service endpoint class.

After a service endpoint is defined, it's deployed in a container that implements the JAX-RPC runtime system on the server. For example, the service endpoint can be deployed as a servlet in a servlet container, or a stateless session bean in an EJB container. The JAX-RPC specification defines a non-normative deployment descriptor for an endpoint deployed in a servlet container. The JAX-RPC Reference Implementation, which is part of Java WSDP 1.0_01 FCS, supports only deployment in a servlet container.

Artifacts

In order to handle communication between a client and a service endpoint, JAX-RPC needs various classes, interfaces, and other files on both the client and server side of the communication. These files are collectively called artifacts. An implementation of JAX-RPC must provide a tool to generate these artifacts. The specification does not require any specific tool to do this -- it's implementation dependent. In the Java WSDP, the tool is wscompile.

Use a mapping tool, such as the wscompile tool in the Java WSDP, to generate artifacts such as stubs, ties, serializers, and deserializers. You can also use the wscompile tool to produce a WSDL document from a JAX-RPC service endpoint definition, or produce a JAX-RPC service endpoint definition from a WSDL document.

Among the required artifacts for client-server communication, are stubs, ties, serializers, and deserializers. Stubs are classes that represent a service endpoint on the client. This allows a JAX-RPC client to invoke a remote method on a service endpoint as though the method were local. You can learn more about stubs in Stubs. A tie is the server-side analog to a stub. It represents the service endpoint on the server. Serializers and deserializers are classes that are used to serialize a Java type to XML, or XML to Java, respectively.

Java-WSDL/XML Mappings

Recall that JAX-RPC relies on WSDL for the description of Web services. In fact, being able to access a WSDL description of a Web service is a requirement for JAX-RPC interoperability -- remember JAX-RPC does not require both the client and server to be on a Java platform. To meet this WSDL requirement, all JAX-RPC implementations must be able to produce a WSDL document from a service endpoint definition. The JAX-RPC specification defines the mapping between the definition of a JAX-RPC service endpoint and a WSDL service description. For example, it specifies that a service endpoint interface is mapped to a WSDL portType structure, and the methods defined in the service endpoint interface are mapped to operation elements in the portType structure. A JAX-RPC implementation must be able to produce a Web service description according to the mappings defined in the JAX-RPC specification. As is the case for generating artifacts, the specification does not require any specific tool to do this. In the Java WSDP, the tool is wscompile. In other words, you can use the wscompile tool to generate artifacts such as stubs and ties, and also use it to produce a WSDL document from a JAX-RPC service endpoint definition. The tool also works in reverse -- you can use it to produce a JAX-RPC service endpoint definition from a WSDL document. Here, for example, is a WSDL document that the wscompile tool generates for the StockQuoteService service endpoint.

The JAX-RPC specification also lists the Java data types that a JAX-RPC implementation must support. For example, it requires support for Java primitive data types such as boolean, byte, int, and double. In addition, it specifies the mapping of each supported Java data type to an XML data type, that is, a data type defined in XSD (XML Schema Definition language). For example, the Java data type boolean maps to the XML data type xsd:boolean. Complying with these specifications, enables JAX-RPC implementations on the client and server to interchange method parameters and return data in an intelligible way.

Bindings

The JAX-RPC specification does not mandate any specific XML-based protocol for exchanging and transporting information. But it does require an interoperable JAX-RPC system to support the SOAP 1.1 with attachment protocol and the HTTP 1.1 network transport protocol.

Notice the binding element in the WSDL document that the wscompile tool generated for StockQuoteService. In generating a WSDL document, a mapping tool configures one or more protocol bindings for each service endpoint. The binding ties an abstract service endpoint definition to a specific protocol and transport. The binding in the StockQuoteService example is SOAP 1.1 over HTTP. It's important to note that the JAX-RPC specification does not mandate any specific XML-based protocol for exchanging and transporting information. However, the specification does state that "An interoperable JAX-RPC system is required to support the SOAP 1.1 with attachment protocol." What this means is that for interoperability, a JAX-RPC implementation must support SOAP 1.1 with attachments, but additional protocols can be supported. Similarly, the JAX-RPC specification requires an implementation to support HTTP 1.1 network transport protocol. However an implementation can support additional transport protocols. The JAX-RPC 1.0 reference implementation supports SOAP 1.1 and SOAP 1.1 with Attachments as the XML-based protocols for information exchange, and HTTP 1.1 as the network transport protocol.

Stubs, Dynamic Proxies, and Dynamic Invocation

A JAX-RPC client can invoke a remote method on a service endpoint in various ways:

Stubs

A stub is designed to simplify remote method calls, that is, by making them appear like local method calls.

Stubs are used when a JAX-RPC client knows what method to call and how to call it (for example, what parameters to pass). Invoking a remote method through a stub is like invoking a remote method using the Java Remote Method Invocation (RMI) system. As is the case for RMI, in JAX-RPC, a stub is designed to simplify remote method calls, that is, by making them appear like local method calls. A local stub object is used to represent a remote object. To make a remote method call, all a JAX-RPC client needs to do is make the method call on the local stub. The stub (using the underlying runtime environment) then formats the method call and directs it to the server -- this process is called marshalling. On the server, a class called a tie (also called a skeleton) unmarshals this information and makes the call on the remote object. The process is then reversed for returning information to the client.

The following figure illustrates what happens when a JAX-RPC client invokes a remote method through a stub.

JAX-RPC
Click image to enlarge



RPC Call on the client:

1. A client application makes an RPC call on a local object called a stub.

2. The stub converts the RPC call to JAX-RPC runtime system requests.

3. The JAX-RPC runtime system maps the requests to a SOAP message and transmits it as part of an HTTP request.

RPC Call on the the server:

4. The JAX-RPC runtime system extracts the SOAP message from the HTTP request, and maps it to a method call on a local object called a tie.

5. The tie invokes the method call on the Web service.

6. The Web service processes the request.

RPC response on the client:

10. The JAX-RPC runtime system extracts the SOAP message and maps it to a response on the stub.

11. The stub returns the response to the client application.

12. The client application gets (and processes) the response.

RPC response on the server:

7. The Web service returns the response.

8. The tie converts the response to JAX-RPC runtime system requests.

9. The JAX-RPC runtime system maps the response to a SOAP message and transmits it as part of an HTTP request.



As mentioned in Artifacts, an application developer uses a mapping tool, such as the wscompile tool, to generate the stub (as well as other artifacts). There are actually two ways to generate the stub. The stub can be generated from the service endpoint definition or from a WSDL document. An application developer can use the wscompile tool to generate the stub using either approach.

In order to use a stub, it has to be configured with information such as the service endpoint address. If a stub is generated from a WSDL document, the mapping tool configures the stub using information in the WSDL document. However if the stub is generated from a service endpoint interface, the developer needs to provide the configuration information. JAX-RPC provides a client-side API, javax.xml.rpc.Stub, to specify this information.

Here, for example, is part of what the code might look like for a client class that uses a stub to invoke the getLastTradePrice method. In this example, the stub was generated from a service endpoint definition:

import javax.xml.rpc.Stub;
import javax.xml.rpc.JAXRPCException;

public class SqpClient {
    public static void main(String[] args) {
        try {
            StockQuoteProvider_Stub sqp = 
                (StockQuoteProvider_Stub)(
new StockQuoteService_Impl().getStockQuoteProviderPort());            
            sqp._setProperty(
                       Stub.ENDPOINT_ADDRESS_PROPERTY,
                                 "http:// ...")
	    float quote = sqp.getLastTradePrice(
	                             "ACME");
	    	    
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Notice how the client class gets an instance of the stub. The JAX-RPC specification does not specify a standard way to do this. The approach used here assumes that the stub was generated using the wscompile tool. The StockQuoteService_Impl class is a client-side implementation class that is generated by the wscompile tool for the StockQuoteService service endpoint. The StockQuoteService_Impl class provides a method, getStockQuoteProviderPort, to get a reference to the stub for the endpoint. Also notice how the endpoint address is set on the stub using the _setProperty method. Finally, notice the JAXRPCException class. JAXRPCException is thrown from the core JAX-RPC APIs to indicate an exception related to the JAX-RPC runtime system.

Dynamic Proxies

A dynamic proxy is a class that dynamically supports service endpoints at runtime, without the need to generate stubs. A client creates a dynamic proxy by calling the getPort method of the interface javax.xml.rpc.Service. In making the call, the client specifies the port for a service endpoint and the service endpoint interface. The method returns a dynamically built implementation of the service endpoint. The client can then invoke a method on the dynamic proxy. For example, here is what the code might look like for a client class that uses a dynamic proxy to invoke the getLastTradePrice method:

import java.net.URL;
import javax.xml.rpc.Service;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;

public class SqpClient {

    public static void main(String[] args) {
        try {
            String UrlString = "http://...";
            String nameSpaceUri = "http://proxy.org/wsdl";
            String serviceName = "StockQuoteService";
            String portName = "StockQuoteProviderPort";

            URL sqpWsdlUrl = new URL(UrlString);
                        
            ServiceFactory serviceFactory =
              ServiceFactory.newInstance();
                        
            Service sqpService =
              serviceFactory.createService(sqpWsdlUrl, 
              new QName(nameSpaceUri, serviceName));
                            
            StockQuoteProvider sqp = 
             (StockQuoteProvider) sqpService.getPort(
              new QName(nameSpaceUri, portName), 
              StockQuoteProvider.class); 
            
	    float quote = sqp.getLastTradePrice("ACME");
	    	    
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Notice how the client class uses the createService method of the ServiceFactory class to create an instance of the service. The method takes as input the URL of the WSDL document location for the service, and a QName object that provides the qualified name for the service.

Dynamic Invocation Interface (DII)

Sometimes a JAX-RPC client needs to invoke a remote method dynamically. For example, consider a scenario where the client doesn't know the remote method name or its signature until run time. In cases like these, the client can use the JAX-RPC Dynamic Invocation Interface (DII). As is the case for dynamic proxies, dynamic invocation does not involve the use of stubs.

To use the DII, a client:

  • Creates a Call object. The object provides an in-memory model of the WSDL description of a service.
  • The JAX-RPC Service class acts as a factory for these objects.
  • Creates the call using one of the createCall methods on the Service object. The configuration of a Call object includes the following properties:
    • The name of a specific operation
    • The port type for the service endpoint
    • Binding properties such as the SOAPAction header URI for the SOAP binding to HTTP
    • The name, type, and mode of input and output parameters
    • The return type
    If the service endpoint implementation was generated from a WSDL document, the WSDL description can provide most of the configuration information. Otherwise, a client uses setter methods to specify the configuration information.
  • Invokes the remote method on the Call object.

DII supports two types of invocation: synchronous request-response mode and one-way mode. In synchronous request-response mode invocation, the client uses the invoke method of the Call object to invoke a remote method. The client then waits (specifically, the client thread blocks) until the operation is complete, that is, until a response (or exception) is returned. In one-way invocation mode, the client uses the invokeOneWay method of the Call object to invoke a remote method. In this case, the client doesn't block -- in other words, the client continues processing without waiting for the operation to complete.

Here is an example of a client that uses DII:

import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.rpc.ParameterMode;
import javax.xml.rpc.JAXRPCException;
import javax.xml.namespace.QName;
import javax.xml.rpc.ServiceFactory;

public class SqpClient {

    private static String qnameService = 
                      "StockQuoteService";
    private static String qnamePort = 
                  "StockQuoteProviderPort";                  
    private static String ENCODING_STYLE_PROPERTY =
          "javax.xml.rpc.encodingstyle.namespace.uri"; 
    private static String NS_XSD = 
                    "http://www.w3.org/2001/XMLSchema";
    
    public static void main(String[] args) {
        try {
            factory = ServiceFactory.newInstance();
            Service service = 
              factory.createService(new QName(
                                      qnameService));
            QName port = new QName(qnamePort);
            Call call = service.createCall(port);
            
            call.setTargetEndpointAddress(
                                       endpointAddress);
                                       
            call.setProperty(
                          Call.SOAPACTION_USE_PROPERTY, 
                          new Boolean(true));
            call.setProperty(
                          Call.SOAPACTION_URI_PROPERTY, 
                          "");
            call.setProperty(ENCODING_STYLE_PROPERTY,
                           URI_ENCODING);             
                           
            call.addParameter("String_1", QNAME_TYPE_STRING, 
                            ParameterMode.IN);
            call.addParameter("String_2", QNAME_TYPE_STRING, 
                            ParameterMode.OUT);
                            
            call.setReturnType(QNAME_TYPE_INT);
            
            call.setOperationName(
                            new QName(BODY_NAMESPACE_VALUE, 
                            "getLastTradePrice"));
            
            Object[] inParams = new Object[] {"ACME"};
            Integer ret = (Integer) call.invoke(inParams);
            Map outParams = call.getOutputParams();
            String OutValue = (String)outParams.get("param2");
            
            } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}            

In this example:

  • The newInstance method of the ServiceFactory class creates a ServiceFactory object.
  • The createService method of the ServiceFactory object creates a Service object. The method call specifies a qualified name for the service.
  • The createCall method of the Service object creates a Call object. The method call specifies a qualified name for the service endpoint.
  • Setter methods such as setTargetEndpointAddress and setOperationName are used to configure the Call object.
  • The setProperty method is used to set standard properties that are listed in the JAX-RPC specification, such as SOAPACTION_USE_PROPERTY which indicates whether or not SOAPAction is used. In this example, SOAPACTION_USE_PROPERTY is set to true, so SOAPAction is used.
  • The addParameter method is used to add a parameter and type for the operation specified in the setOperationName method. Note that the values of these parameters are obtained from the WSDL document for the service.
  • The setReturnType method is used to set the return type for the operation specified in the setOperationName method.
  • The invoke method invokes the operation specified in the setOperationName method, using a synchronous request-response interaction mode. The method call specifies the input parameters for the invocation.
  • The getOutputParams method returns a Map of {name, value} for the output parameters of the invoked operation.

For a more complete DII example, see A JAX-RPC Example.

JAX-RPC Packages

The JAX-RPC API comprises a number of packages. Two of the packages are used in the examples that illustrate how to use stubs, dynamic proxies, and the Dynamic Invocation Interface. Those packages are:

  • javax.xml.rpc. This package contains the core JAX-RPC APIs for the client programming model. This includes interfaces and classes that are used by a JAX-RPC client.
  • The interfaces in the package are:

    Stub This is the common base interface for stub classes. All generated stub classes are required to implement the Stub interface.
    Service This interface provides support for creating a dynamic proxy and for creating a Call object.
    Call This interface provides support for the dynamic invocation of an operation on a service endpoint.

    An important class in the package is:

    ServiceFactory This is an abstract class that provides a factory for creating Service objects.
  • javax.xml.namespace. This package contains a class that provides a qualified name. The class is:

    QName This class represents the value of an XML qualified name as specified in XML Schema Part2: Datatypes specification.

Other packages in the JAX-RPC API are intended primarily for JAX-RPC implementations. For example, they provide interfaces and classes for Java-XML serialization and deserialization, for handling SOAP messages, and for data type mapping.

Note that the JAX-RPC API also depends on another package, javax.xml.soap, that is defined by the SOAP with Attachments API for Java (SAAJ) 1.1 specification. As its name implies, SAAJ is an API that is used to represent a SOAP message with attachments. The JAX-RPC API has a number of dependencies on the SAAJ API. For example, it uses elements of the javax.xml.soap package to represent the mapping of literal fragments in a SOAP message.

The wscompile Tool

wscompile is a mapping tool provided in the Java WSDP to generate stubs, ties, and other artifacts. You can also use the wscompile tool to produce a WSDL document from a JAX-RPC service endpoint definition, or produce a JAX-RPC service endpoint definition from a WSDL document.

wscompile and a companion tool, wsdeploy, replace the xrpcc tool that was provided in earlier releases of the Java WSDP. The xrpcc tool is still provided in Java WSDP 1.0_01, however its use is deprecated.

You have the option of running the wscompile tool to produce only client-side artifacts such as stubs, server side artifacts such as ties, or both client and server-side artifacts. In any case, you need to provide a configuration file as input to the tool. The configuration file is an XML file that contains information needed by the tool, such as what artifacts to generate, data for the generated WSDL document (if a WSDL document is generated from a JAX-RPC service endpoint definition), or data for the generated service endpoint definition (if the service endpoint definition is generated from a WSDL document).

Here is an example of a configuration file:

<?xml version="1.0" encoding="UTF-8"?> 
<configuration xmlns="http://java.sun.com/xml/ns/jax-
            rpc/ri/config"> 
   <service name="StockQuote" 
      targetNamespace="http://example.com/stockquote.wsdl" 
      typeNamespace="http://example.com/stockquote/types" 
      packageName="stockqt"> 
      <interface name="stockqt.StockQuoteProvider" 
         servantName="stockqt.StockQuoteServiceImpl"/> 
   </service> 
</configuration>

Notice that the file starts with a configuration element. This element identifies the namespace for the configuration file, which always must be http://java.sun.com/xml/ns/jax-rpc/ri/config. Next, the service element identifies the input as coming from the service endpoint definition. This information will be used by the wscompile tool to generate a WSDL document as well as artifacts. If the input was a WSDL document, the configuration file would specify a wsdl element instead of a service element. In that case, the tool would use that information to generate a service endpoint definition.

The service element identifies:

  • The name of the service: StockQuote
  • The namespace for the service: http://example.com/stockquote.wsdl
  • The type namespace for the service: http://example.com/stockquote/types
  • The package name for artifacts generated by the wscompile tool: stockqt

The interface element within the service element structure identifies the service endpoint interface (StockQuoteProvider) and the interface implementation (the "servant name"): StockQuoteServiceImpl.

In addition to the stubs and ties that it generates, the wscompile tool also generates a model file. This model file is designed to be used by the wsdeploy tool in generating a deployable J2EE WAR (web archive) file for a Web service. The model file is an XML file that contains information about the service, such as dependency relationships.

To run the wscompile tool, you run a script (in UNIX) or a batch file (in Windows). The UNIX syntax is:

wscompile.sh options config-filename

The Windows syntax is:

wscompile.bat options config-filename

where options are one or more control options for the wscompile tool, and config-filename is the name of a configuration file.

Some of the wscompile options are:

-gen:both Generates client-side and server-side artifacts (and depending on the contents of the configuration file, a WSDL document or a service endpoint definition)
-gen:client Generates client-side artifacts (and depending on the contents of the configuration file, a WSDL document or a service endpoint definition)
-gen:server Generates server-side artifacts (and depending on the contents of the configuration file, a WSDL document or a service endpoint definition)
-keep Keeps the generated source files after they are compiled
-classpath Specifies where to find the input class files
-d Specifies a directory for generated output
-model Writes the generated model to the specified file

If you invoke the wscompile tool without specifying an option, it will display the tool invocation syntax and a description of all the options.

Here's an example of an wscompile tool invocation in UNIX. (Although shown on two lines, the command is specified on one line.).

wscompile.sh -gen:both -keep -d classout 
  -model wscmodel.xml.gz config.xml  

Assume that the contents of the configuration file (config.xml) are the same as shown in the earlier configuration file example. As a result, the wscompile tool will generate client-side and server-side artifacts. It will also generate a WSDL document from the service endpoint definition identified in the configuration file. Source files that are generated by the wscompile tool will be kept, the generated classes will be placed in the classout directory, and the model will be written to file wscmodel.xml.gz.

The wsdeploy Tool

wsdeploy is a tool provided in the Java WSDP to generate a deployable WAR file for a service. The tool takes as input a "raw" (that is, not yet deployable) WAR file for the service, and generates a deployable WAR file. A raw WAR file contains the following components:

  • META-INF
    • MANIFEST.MF — Contains information about the file packaged in the WAR file.
  • WEB-INF
    • web.xml — Contains information about the service, such as its display name and description.
    • model.xml.gz — A compressed version of the model.
    • jaxrpc-ri.xml — The deployment descriptor for the service.
    • classes — A directory that contains the bulk of the components.

Typically, you create a raw WAR file with a GUI development tool or through a build tool such as the Ant Build Tool packaged in the Java WSDP. A deployable WAR file contains an updated version of the web.xml component. The updated version contains additional information about the service, such as the servlet class for the service endpoint. The deployable WAR file also contains a runtime deployment descriptor, jaxrpc-ri-runtime.xml. The descriptor contains runtime information, such as the class for the tie.

In generating the file, wsdeploy examines the deployment descriptor, jaxrpc-ri.xml. If the deployment descriptor identifies a model file, the information in the model file is used in generating the deployable WAR file. If the deployment descriptor does not identify a model file, the wsdeploy tool generates the model.

Also, note that in generating the file, wsdeploy runs wscompile with the -gen:server option. In other words, wsdeploy generates server-side artifacts (such as a tie), and can also generate a WSDL document or a service endpoint definition. So rather than running wscompile explicitly to generate server-side artifacts (and possible a WSDL document or a service endpoint definition), you can run wsdeploy to generate the same artifacts, classes, and WSDL file.

To run the wsdeploy tool, you run a script (in UNIX) or a batch file (in Windows). The UNIX syntax is:

wsdeploy.sh options war-filename

The Windows syntax is:

wscompile.bat options war-filename

where options are one or more control options for the wsdeploy tool, and war-filename is the name of a raw WAR file.

Some of the wsdeploy options are:

-o Specifies where to place the generated WAR file (this is a required option)
-keep Keeps temporary files generated during the process
-classpath Specifies where to find the input class files
-tmpdir Specifies a directory for temporary files

If you invoke the wsdeploy tool without specifying an option, it will display the tool invocation syntax and a description of all the options.

Here's an example of an wsdeploy tool invocation in UNIX:

wsdeploy.sh -o target.war raw.war  

In this example, the wsdeploy tool will take the raw WAR file, raw.war, and generate a deployable version, named target.war.

A JAX-RPC Example

This section presents an example of JAX-RPC in use. The example is based on a sample application that uses JAX-RPC (as well as JAXM) to access Web services. The example also uses tools, such as the wscompile tool, that are provided in the Java WSDP. For instructions on building and running the sample application, see Build and Run the Sample Application.


Part 1 of this series presented an example that illustrated how a fictitious company named BooksToGo used JAXR to register a Web service, and how another fictitious company, BoomingBusiness.com, used JAXR to discover the service. Recall that BoomingBusiness.com provides a Web site to its employees. The Web site is a portal to a variety of employee services. One of the services that BoomingBusiness.com plans to make available through its Web site is an online service for ordering books. BooksToGo is a provider of that service. (The BoomingBusiness.com employee portal will access the book ordering service using JAXM. This is explained further in A JAXM Example.)

Let's extend the example. Assume that BoomingBusiness.com decides to add another employee service to its portal: a retirement planning service. Using this service, an employee could search for available retirement funds, identify which companies provide those funds, and then get quotes from prospective providers for their services. The employee could then select a provider, and invest money in the funds of choice.

As was the case for the book ordering service, BoomingBusiness.com wants to implement this extension as a Web services-based solution. In particular, BoomingBusiness.com plans to extend the portal so that when an employee requests the retirement planning service, an underlying program dynamically searches a business registry for retirement fund providers. BoomingBusiness.com's IT staff further decides to use JAX-RPC for client-to-provider interactions such as getting a list of funds that the providers offer, and getting quotes from providers.

Pan American Services and Retirements Specialists are two companies that specialize in providing retirement services. They are both retirement fund providers. Both companies want to make their retirement services available to clients through JAX-RPC. Let's examine what the retirement fund providers do to make their retirement services available to clients through JAX-RPC. Then let's examine what BoomingBusiness.com does to access the retirement services through JAX-RPC.

The retirement fund providers take the following actions:

BoomingBusiness.com takes the following actions:

Provide the Service Endpoint Interface

For the purposes of this example, assume that the retirement service providers have agreed to support a service endpoint interface named RetirementServiceIF. Here is part of the source code for the RetirementServiceIF class:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface RetirementServiceIF extends Remote {

    public String[] getAvailableFunds( ) 
                                throws RemoteException;
    
    public double getQuote( 
        FundInfo[] reqFunds, double monthlyInvestment )
	 throws RemoteException;
    
    public String confirmQuote( 
      FundInfo[] reqFunds, double monthlyInvestment, 
               EmployeeInfo ei) throws RemoteException;
                
}

The source code shown for the service endpoint interface defines three methods:

  • getAvailableFunds. This method returns the retirement funds offered by a provider.
  • getQuote. This method returns a quote from each provider that offers all the funds that the client requests. The input parameters to the method are an array (reqFunds) that contains the names of the requested retirement funds, and a monthly investment amount (monthlyInvestment) for each fund.
  • confirmQuote. This method confirms that a client has accepted a provider's quote. Like the getQuote method, the input parameters to the confirmQuote method are an array of requested funds, and the monthly investment amount. The method also takes as input an EmployeeInfo object ei that contains information about the employee who is investing in the retirement funds.

To see the complete source code for the RetirementServiceIF class used in the sample application, look here.

Each retirement fund provider implements the RetirementServiceIF service endpoint interface. For example, here is part of the source code for the implementation class provided by Pan American Services. To make things simpler for this example, the funds provided by Pan American Services are specified in the class. In a real-life example, the class would probably access a database to get the names of the funds.

public class PanAmericanRSImpl implements 
                                 RetirementServiceIF {
    public String providerName="PanAmerican";
    private Vector availableFunds = null;

    public PanAmericanRSImpl( )
    {
	availableFunds = new Vector();
	availableFunds.addElement("Old age funds");
	availableFunds.addElement(
	                      "Happy old days funds");
	availableFunds.addElement("Sunrise funds");

    }

    public String[] getAvailableFunds ( ) {
	if ( availableFunds == null ) {
	    return null;
	}

	String[] aFunds = 
	          new String[ availableFunds.size() ];
	availableFunds.copyInto( (Object[])aFunds );
	return aFunds;
    }

    public double getQuote( 
       FundInfo[] rFunds, double monthlyInvestment ) { 
	
	for ( int i=0; i<rFunds.length; i++ )
	{
		FundInfo fi = rFunds[i];
		System.out.println("Requested :"
		          + fi.getFundName() + "=" 
		          + fi.getFundPercent() );	
		if ( !availableFunds.contains( 
		                fi.getFundName() ) ) {
			return 0;
                }

        }
        
                return 3.0;

    }

    public String confirmQuote( FundInfo[] rFunds, 
                             double monthlyInvestment ,
		 EmployeeInfo ei ) {

	for ( int i=0; i<rFunds.length; i++ )
	{
	    FundInfo fi = rFunds[i];
	    System.out.println("Requested :" 
	                + fi.getFundName() + "=" 
	                + fi.getFundPercent() );	
	}

       	return "Fund Request confirmed";
    }

	
}

To see the complete source code for the PanAmericanRSImpl implementation class used in the sample application, look here.

After coding the classes for the service endpoint definition, the service providers compile the classes.

Register the Retirement Service

Pan American Services and Retirements Specialists use the JAXR API in the Java WSDP package to register their retirement services. They choose to register the services in a UDDI registry. (In the sample application, the UDDI registry used is the Java WSDP Registry Server v1.0_02 provided in the Java WSDP v1.0_01.) For a description of the steps involved in registering a Web service, see the JAXR example in Part 1 of this series.

Each provider publishes information about its retirement service. For example, Pan American Retirement Service publishes the following information:

Business Name Pan American Services
Contact Information Primary Contact: Bhakti Mehta
Phone number: (408)1234567
Email Address: bhakti.mehta@panamerican.com
Classification Scheme (classification, code) NAICS (Pension Funds, 52511)
Service Retirement Service
Service Binding Description: JAXRPC-FCS (SOAP/HTTP) based binding
Access Point: http://localhost:8080/PanAmericanRS/jaxrpc/RetirementServiceIF

Notice the classification code, 52511. This is the North American Industry Classification System (NAICS) code for pension funds (in other words, retirement funds). To find retirement fund providers, BooomingBusiness.com's application program will query a registry for entries that have the pension fund code in their classification.

Notice too the binding information: JAXRPC-FCS (SOAP/HTTP) based binding. This identifies the service as accessible through JAX-RPC. In looking for retirement fund providers, BooomingBusiness.com's application program will look for entries that meet this criteria. The access point identifies the URL for the service endpoint. JAX-RPC clients will specify this URL to contact the service. In this example, the URL is a localhost URL, so that the service endpoint is actually on your machine. In a real Web service deployment, the service endpoint would probably be on a different machine.

The sample application includes a class that registers the retirement services. To see the source code for the class, look here.

Generate the Artifacts

Each retirement service provider uses the wscompile tool to generate the artifacts needed for a client to access and use the service. For example, here is a command that Retirement Specialists executes in the UNIX environment to generate the artifacts (although shown on two lines, the command is entered on one line):

wscompile.sh -classpath toolclass -gen:both -keep 
  -d classout -model modelfile config.xml

toolclass, classout, and modelfile are representative. Retirement Specialists specifies actual class paths for toolclass and classout. They specify a file name (and path) for modelfile. Based on the options specified in the command, the wscompile tool generates both client-side and server-side artifacts, keeps source files that it generates, and puts the generated classes in the classout directory. It also creates and stores the model file in the location identified by modelfile.

In the sample application, the wscompile tool is invoked from an XML file. Here are the contents of the file. Notice the part of the file that invokes the wscompile tool. For example, here's the XML code that invokes the wscompile tool in UNIX for Retirement Specialists:

  <target name="wscompile-retirementspecialists" 
    if="isNotWindows" >
      <echo message="wscompiling retirement specialists..."/>
	<exec executable="${JWSDP_HOME}/bin/wscompile.sh">
	 <arg line="-classpath ${build}/jaxrpc-providers"/>
	 <arg line="-gen:both"/>
	 <arg line="-keep"/>
	 <arg line="-d ${build}/jaxrpc-providers"/>
	 <arg line="-model"/>
	 <arg line="-d ${build}/jaxrpc-providers/rs-model.Z"/>
	 <arg line="jaxrpc-providers/config/rs-config-rmi.xml"/>
	</exec>
  </target>

Here are the contents of the configuration file, rs-config-rmi.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration
      xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
        <service name="RetirementSpecialistsRS"
             targetNamespace="http://retirementservice.org/wsdl"
             typeNamespace="http://retirementservice.org/types"
             packageName="com.sun.eportal.retirement"
             <interface name="com.sun.eportal.RetirementServiceIF"
             servantName="com.sun.eportal.retirement.RetirementSpecialistsImpl"/>
        </service>
</configuration>

Notice that it includes a service element. As a result, the wscompile tool will generate a WSDL file from the service endpoint definition identified in the configuration file. Here is the WSDL file for the Retirement Specialists service.

Here is the model file created by the wscompile tool for Retirement Specialists.

Deploy the Service

Both retirement service providers want to deploy their services in a J2EE-compliant container. (In the sample application, the container is Tomcat.) They also decide to implement the service endpoints for their services as servlets. To deploy Web server-based components such as servlets in a J2EE-compliant container, each service provider needs to create a WAR file. The service providers create their respective WAR files using J2EE tools. However the WAR files are still raw. To make their WAR files deployable, each service provider uses the wsdeploy tool. For example, here is a command that Retirement Specialists executes in the UNIX environment to run the wsdeploy tool (although shown on three lines, the command is entered on one line):

wsdeploy.sh -keep tmpdir tempdir 
  -o RetirementSpecialistsRS.war  
  RetirementSpecialistsRSraw.war

tempdir is representative. Retirement Specialists specifies an actual class path for temporary files generated by the wsdeploy tool. The wsdeploy tool takes the WAR file, RetirementSpecialistsRSraw.war, as input. Based on the options specified in the command, the tool generates a deployable WAR file, RetirementSpecialistsRSraw.war. Temporary files generated during the process are stored in the specified directory.

Create the Client

BoomingBusiness.com envisions the following flow of events for their retirement planning service. After an employee clicks a "Retirement Services" link in the employee portal:

Click to enlarge each image

1. The employee portal displays a list of available retirement funds 2. The employee selects one or more retirement funds, specifies a percentage of money to be invested in each fund, and the total monthly amount of money to be invested.
Available fund Selecting funds
3. Providers that offer all of the selected funds respond with a quote for their services. 4. The employee selects one of the providers that offers a quote.
Provider quotes Provider quotes



The selected provider then sends a note to confirm the transaction.

Here's what BoomingBusiness.com's IT staff plans to implement in support of this interaction:

  • A link for "Retirement Service" in the home page of their employee portal.
  • An "available funds" JavaServer Page (JSP) that displays the table of available retirement funds.
  • A "401kbidding" JSP that displays bids from retirement fund providers. When an employee selects one or more retirement funds in the table of available funds, it opens the 401kbidding JSP.
  • A "fund lister" JavaBean. The available funds JSP uses the fund lister JavaBean to get an aggregated list of available retirement funds. The 401kbidding JSP uses the fund lister JavaBean to get a quote from each provider that offers all of the selected funds.
  • A DII client class. The fund lister JavaBean uses this class to get a list of available funds, and to get quotes from retirement fund providers.
  • A "confirmation" JSP that confirms the transaction. When an employee selects one of the retirement providers that offers a quote, the 401kbidding JSP opens the confirmation JSP.

Let's look at some of these components in more detail.

Available Funds JSP: Here is the source code for the available funds JSP. Notice the use of the fund lister JavaBean. The JSP invokes the populateAvailableFunds method in the fund lister JavaBean to get a list of available funds, and then invokes the getFundHash method in the fund lister to create a hashtable (that is, a table that maps keys to values) for the retrieved funds.

<jsp:useBean id="fundLister" 
 class="com.sun.eportal.FundLister" scope="session" />

     ...
     
     fundLister.populateAvailableFunds();
     Hashtable fundHash = fundLister.getFundHash();  
     ...     

The JSP then displays the retirement funds in a table. The user selects one or more funds, specifies an investment percentage for each, and a monthly investment amount. After the user makes these selections and specifications, the subsequent action is to invoke the 401kbidding JSP:

<form action="401kbidding.jsp">
<TABLE border=1>
<TR> <TH> Funds </TH> <TH> Investment Percentage</TH> </TR>

<%

Enumeration keys = fundHash.keys();
while ( keys.hasMoreElements( ) )
{
        String fundName= (String)keys.nextElement(  );
        String fundNamePercent = fundName + "Percent";
%> 
<TR> <TD>
 ... <%= fundName %> ...</TD> 
 <TD> <INPUT TYPE=text name='<%= fundNamePercent %> ... 
 </TD> </TR>
<%
}
%>
<TR> <TD ...> <...>Investing Money :</FONT> </TD>
<TD> $<INPUT type="text" name="monthlyInvestment" ...>/Month 
</TD> </TR>
...

</TABLE>

401kbidding JSP: Here is the source code for the 401kbidding JSP. Notice that it invokes the getAllQuotes method in the fund lister JavaBean, passing the method an array of the selected funds, and a monthly investment amount. The getAllQuotes method gets quotes from providers that offer all of the selected funds.

<jsp:useBean id="fundLister" 
 class="com.sun.eportal.FundLister" scope="session" />
...
Hashtable quoteHash = fundLister.getAllQuotes( 
                   fundInfoArray, monthlyInvestment );
...

The 401kbidding JSP then displays two tables, one that lists the selected funds, and another that lists the providers and their quotes. The user selects a provider and submits it. This invokes the confirmation JSP.

<FORM method=post action="confirmation.jsp" >

<FONT ...>Requested Funds </FONT>
<TABLE ...>
<TR><TH>Fund Name</TH> <TH>Fund Percent</TH> </TR>
...
</TABLE>

<TABLE ...>
<TR><TH></TH><TH> End Point </TH> 
<TH> Service Fee($) </TH> </TR>
<%
Enumeration keys = quoteHash.keys();
while ( keys.hasMoreElements( ) )
{
  String endpoint = (String)keys.nextElement();
  Double quoteD = (Double)quoteHash.get( endpoint);
%>
<TR> <TD ...><INPUT TYPE=RADIO 
  NAME="endpointRadio" value="<%=endpoint%>"></TD>
  <TD ...> <%= endpoint %> </TD> <TD ...> 
  <%= quoteD %> 
</TD> </TR>
<%
}
%>
<TR> <TD ...> <INPUT TYPE="Submit" value="Confirm"/> 
</TD> </TR>
</TABLE>
</FORM>

Confirmation JSP: Here is the source code for the confirmation JSP. The JSP obtains information about the employee and the employee's retirement fund provider selection. It then calls the getQuote method in the DII client to confirm the transaction.

RSClient_DII rsClient = new RSClient_DII();
String resultString = rsClient.confirmQuote( 
           endPoint, fundInfoArray, monthlyInvest, ei ); 

After the transaction is confirmed, the confirmation JSP uses a bean to store employee information in persistent storage (typically this would be a database):

if (resultString !=  null )
{
int numRows = dbBean.execUpdate( "Update ServiceInfo   
 SET retirementprovider='"" + endPoint + "' 
 WHERE employeeid='" + employeeId + "'" );
   if ( numRows > 0){
   System.out.println("Service Info created successfully");
}

The confirmation JSP then sends a confirmation message:

Hi <%= firstName %> <%= lastName %> ...
...
You will get confirmation email from <%= endPoint %> 
with all the details.
... 	

Thank you for using EmployeePortal
...

Fund Lister JavaBean: Here is the source code for the fund lister JavaBean. Notice the populateAvailableFunds method. This is the method that the fund lister JavaBean uses to search for appropriate providers. The populateAvailableFunds method uses a query method in a client query object to search a Web services registry for providers classified as pension fund (in other words, retirement fund) providers. The parameters passed to the query method comprise the NAICS classification scheme for pension funds.

public void populateAvailableFunds ( ) {
    try {
        String cScheme="ntis-gov:naics";
        String keyName="Pension Funds";
        String keyValue="52511";
        String serviceName="Retirement Service";

        ...

        ClientQuery clientQuery = new ClientQuery( );
        Vector serviceProviderInfoVector = 
          clientQuery.query( cScheme, keyName, keyValue);    
     
        ...

After the the query returns information from the registry, the fund lister JavaBean examines the binding information exposed by the candidate providers. If the binding is JAX-RPC, the fund lister JavaBean adds the provider's service endpoint to an array:

Vector jaxrpcEndpointVector= new Vector();  

for (  int i=0; 
          i< serviceProviderInfoVector.size(); i++ ) {
    ServiceProviderInfo spi = (ServiceProviderInfo)
      serviceProviderInfoVector.elementAt(i);

    if ( spi.getCommunicationType().equals(
                                      "JAXRPC") ) {
        jaxrpcEndpointVector.addElement( 
                                     spi.getEndpoint() );
    }

}
jaxrpcEndpointArray = 
               new String[ jaxrpcEndpointVector.size() ];
jaxrpcEndpointVector.copyInto ( 
                         (Object[])jaxrpcEndpointArray );

The fund lister JavaBean then uses a DII client to get a list of available retirement funds offered by the subset of providers that expose a JAX-RPC binding. It then aggregates the list:

RSClient_DII rsclient_DII = new RSClient_DII();
fundHash =rsclient_DII.getAllAvailableFunds (
                                jaxrpcEndpointArray );

...

The fund lister JavaBean then returns the aggregated list to the available funds JSP for display in a table.

After a user selects one or more funds and specifies investment amounts, the available funds JSP invokes the 401kbidding JSP, which, in turn, invokes the getAllQuotes method in the fund lister JavaBean. Here is the source code for the getAllQuotes method. It calls the getAllQuotes method in the DII client to get a list of quotes.

    public Hashtable getAllQuotes (  
                 FundInfo[] reqFundsInfos, double mi ) {

	RSClient_DII rsclient_DII = new RSClient_DII();
        Hashtable quoteHash = 
         rsclient_DII.getAllQuotes (jaxrpcEndpointArray,
		 reqFundsInfos, mi );

	return quoteHash;

    }

Client Query Class: Here is the source code for the client query class. The class uses JAXR to search a Web services registry. Notice how the query method in the class searches the registry for organizations that meet the supplied classification scheme, and retrieves information about service providers that meet the classification criteria:

ClassificationScheme classificationScheme = 
  queryManager.findClassificationSchemeByName(
                             findQualifiers,  cName );
Classification classification = 
  lifeCycleManager.createClassification( 
  classificationScheme, keyName, keyValue );
  
...

BulkResponse response =
  queryManager.findOrganizations(findQualifiers,
             null, classifications, null, null, null);
Collection orgs = response.getCollection();  

For more information about using JAXR to search a Web services registry, see Part 1 of the series.

DII Client: Here is the source code for the DII client class. The fund lister JavaBean calls the getAllAvailableFunds method in the class to get an aggregated list of available funds. The method call specifies one argument: the array of endpoint addresses for the providers that meet the selection criteria (that is, pension funds) and that expose a JAX-RPC binding. The getAllAvailableFunds method uses the getAvailableFunds method to build the list of funds. Notice how the getAvailableFunds method creates a serializer and deserializer for serializing Java data types to XML, and XML to Java, respectively:

SerializerFactory stringArraySerializerFactory = 
    new SingletonSerializerFactory(stringArraySerializer);
DeserializerFactory stringArrayDeserializerFactory =
    new SingletonDeserializerFactory(stringArraySerializer);

It then creates the Service and Call objects for the DII call. (In this example, the local part of the qualified name for the Service is explicitly specified, that is, "PanAmericanRS". In general, you would obtain the qualified name from a registry.)

ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(
                          new QName("PanAmericanRS"));

...	
Call call = service.createCall();
...

The getAvailableFunds method then configures the Call object.

call.setPortTypeName(port);
call.setTargetEndpointAddress(endpointAddress);

call.setProperty(Call.SOAPACTION_USE_PROPERTY, new Boolean(true));
call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
call.setProperty(ENCODING_STYLE_PROPERTY, 
    SOAPConstants.URI_ENCODING);
    
call.setReturnType(stringArrayTypeQname);
        call.setOperationName(new QName(bodyNamespaceValue,
          "getAvailableFunds"));


The getAvailableFunds method then gets the available funds. Notice the use of the invoke method of the Call object. This invokes the specified operation ("getAvailableFunds") in synchronous request-response mode. The DII client will wait until the operation completes before continuing.

call.setReturnType(stringArrayTypeQname);
call.setOperationName(new QName(bodyNamespaceValue,
     "getAvailableFunds"));
System.out.println("Invoking available Funds");
String[] avFunds = (String[])call.invoke(null);
if ( avFunds != null ) {
   for ( int i=0; i< avFunds.length; i++ ) {
       System.out.println(
        " DII -Available Fund[" + i + 
        " ]-> " + avFunds[i] );
}

Another method of interest in the DII client is getAllQuotes. This method is called by the fund lister JavaBean to get quotes from providers that offer all of the funds that the user selected. The fund lister JavaBean invokes the method with three arguments: the array of endpoints for retirement fund providers, the selected funds, and the monthly investment. The getAllQuotes method uses the getQuote method to get the quotes. The getQuote method uses the newBeanCall object to create the Service and Call objects for the DII call, and the newCall object to set the port type and endpoint address for the Call object. The getQuote method then specifies the operation for getting the quotes (getQuote), and parameters for the operation. It then invokes the operation:

Call call = newBeanCall(endpointAddress,  RETIREMENT_SERVICE,
             RETIREMENT_BODY_NAMESPACE, RETIREMENT_PORT );
...

call.setOperationName(new QName(RETIREMENT_BODY_NAMESPACE, 
            "getQuote"));
call.addParameter( "arrayOfFundInfo_1",  fundInfoArrayTypeQname, 
            ParameterMode.IN ); 
call.addParameter( ""double_2",  QNAME_TYPE_DOUBLE,
            ParameterMode.IN ); 

Object[] params = new Object[2];
params[0] = reqFundInfos;
params[1] = new Double( mi ); 

quoteObject = (Double)call.invoke( params );
...

Notice also the confirmQuote method. This method is called by the confirmation JSP to confirm the transaction between the employee and the retirement fund provider. The confirmation JSP invokes the confirmQuote method with four arguments: the endpoint of the selected retirement fund provider, an array that contains information about the selected funds, the monthly investment amount that the employee specified, and information about the employee. As is the case for the getQuote method, the confirmQuote method uses the newBeanCall object to create the Service and Call objects for the DII call, and the newCall object to set the port type and endpoint address for the Call object. The confirmQuote method then specifies the operation for confirming the transaction (confirmQuote), and parameters for the operation. It then invokes the operation:

Call call = newBeanCall(endpointAddress,  RETIREMENT_SERVICE,
             RETIREMENT_BODY_NAMESPACE, RETIREMENT_PORT );
...

call.setOperationName(new QName(RETIREMENT_BODY_NAMESPACE, 
            "confirmQuote"));
call.addParameter( "arrayOfFundInfo_1",  fundInfoArrayTypeQname, 
            ParameterMode.IN ); 
call.addParameter( ""double_2",  QNAME_TYPE_DOUBLE,
            ParameterMode.IN ); 
call.addParameter( "EmployeeInfo_3",  employeeInfoQname,
			 ParameterMode.IN );            

Object[] params = new Object[3];
params[0] = reqFundInfos;
params[1] = new Double( mi );
params[2] = ei; 

confirmationMessage = (String)call.invoke( params );
...



[<<BACK] [TOP] [NEXT>>]