Download FAQ History |  | API Search Feedback

> ## Advanced JAX-RPC Examples

> This section describes the code examples in the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/` directory. To understand these examples, you should already be familiar with the following:

> - Ant
> - JAX-RPC fundamentals
> - SOAP
> - WSDL
> - WS-I Basic Profile

> The following sections describe the advanced examples:

> - SOAP Message Handlers Example
> - Advanced Static Stub Example
> - Advanced Dynamic Proxy Example
> - Advanced DII Client Example

> Note: Before proceeding, make sure that you've followed the instructions in Setting Up for setting the `PATH` variable and editing the `common/build.properties``` file.

> ### SOAP Message Handlers Example

> JAX-RPC makes it easy to develop Web services and clients because it shields application developers from the underlying SOAP messages. Instead of writing code to build and parse SOAP messages, application developers merely implement the service methods and invoke them from remote clients. The handler processing is hidden from the JAX-RPC client and service implementation code.

> However, there are times when you might want to access the SOAP messages that flow between JAX-RPC clients and services. For example, for auditing purposes, you might want to log every invocation of a service method. Or, you might want to encrypt remote calls at the SOAP message level. These logging and encrypting operations can be implemented with SOAP message handlers.

> A SOAP message handler is a stateless instance that accesses SOAP messages representing RPC requests, responses, or faults. Tied to service endpoints, handlers enable you to process SOAP messages and to extend the functionality of the service. For a given service endpoint, one or more handlers may reside on the server and client.

> #### Handler Processing

> A SOAP request is processed as follows:

> - The client handler is invoked before the SOAP request is sent to the server.
> - The service handler is invoked before the SOAP request is dispatched to the service endpoint.

> A SOAP response is processed in this order:

> - The service handler is invoked before the SOAP response is sent back to the client.
> - The client handler is invoked before the SOAP response is transformed into a Java method return and passed back to the client program.

> A SOAP fault is processed in the same manner as a SOAP response.

> Clients and servers may have multiple handlers, which are configured into handler chains. For example, in a client handler chain with three handlers, the first handler processes the SOAP request, then the second processes the request, and then the third. When the third handler finishes, the request is sent to the server.

> #### Overview of Handler Example

> The client and service implementation code are quite simple. The client invokes the service method named `helloServer`, which echoes a `String` back to the client.

> The client JAR file includes the following classes:

> - `HandlerSampleClient` - the client program that invokes `helloServer`
> - `ClientHandler1` - a client request handler

> The service WAR includes these classes:

> - `HandlerTestImpl` - the service implementation class that implements the `helloServer` method
> - `ServerHandler1` - a server request handler
> - `ServerHandler2` - another server request handler, invoked after `ServerHandler1`

> #### Handler Programming Model

> The process for building the service with a handler requires these steps:

> 1. Write the code for the following:
> 2. service endpoint interface
> 3. service implementation class
> 4. server handler classes
> 5. Create the `jaxrpc-ri.xml` file.

> Read by `wsdeploy`, the `jaxrpc-ri.xml` file has information about the service handlers. For details see the section, The Service jaxrpc-ri.xml File.

> 6. Create the `web.xml` file.
> 7. Compile the code from step 1.
> 8. Package the `web.xml` file, `jaxrpc-ri.xml` file, and compiled classes, into a raw WAR file (`raw.war`).
> 9. Run `wsdeploy` to cook the raw WAR file and create a deployable WAR file (`handler.war`).
> 10. Deploy the WAR file.

> The deployed service has this endpoint address URL:

>     http://localhost:8080/handler/test

> For a client with a handler, do the following:

> 1. Code the client program and the handler.
> 2. Create the `config.xml` file.

> This file is read by `wscompile` and contains information about the client handler. For details see the section, The Client config.xml File.

> 3. Compile the client handler.
> 4. Run `wscompile` to generate the service endpoint interface and client-side classes.

> The `wscompile` command accesses the deployed WSDL file specified in `config.xml`.

> 5. Compile the client program.

> The client is now ready to be run.

> #### Building and Running the Handler Example

> To build and run this example, go to the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/handler` directory and type the following commands:

>     ant build
>     ant deploy
>     ant build-client
>     ant run

> The `ant` `run` tasks executes the client program, which should display the following:

>     ClientHandler1: name = My Client Handler
>     ClientHandler1: adding loggerElement
>     ClientHandler1: adding nameElement
>     HandlerSampleClient: hi there
>     HandlerSampleClient: all done.

> At runtime, the example handlers and service implementation write the following lines to the `<``JWSDP_HOME``>/logs/launcher.server.log` file:

>     ServerHandler1: name = server1
>     ServerHandler2: name = server2
>     ServerHandler1: important message (level 10)
>     ServerHandler2: Request is from Duke
>     TestHandlerImpl: helloServer() message = hi there

> #### Client Handler

> The `ClientHandler1` instance processes the SOAP request before it is transmitted to the service endpoint. The source code for `ClientHandler1` is in the `<``INSTALL``>/jwstutorial12/examples/jaxrpc/advanced/handler/client/` directory.

> Like the other handlers in this example, `ClientHandler1` is a subclass of j`avax.xml.rpc.handler.GenericHandler`:

>     public class ClientHandler1 extends GenericHandler . . .

> `GenericHandler` is an abstract class that implements `javax.xml.rpc.handler.Handler`, an interface that defines the methods required by any handler. Because it provides default implementations for these methods, `GenericHandler` makes it easy to write your own handlers.

> Of the several methods implemented by `GenericHandler`, `ClientHandler1` overrides only these methods:

> - `init`
> - `getHeaders`
> - `handleRequest`

> ##### The init Method of ClientHandler1

> The `init` life-cycle method enables the `Handler` instance to initialize itself. Typically, you'll implement the `init` method to connect to resources such as databases. You can set instance variables in the `init` method, but be aware that a handler is stateless-- the next time a handler is invoked, it might have a different state. Prior to termination, the handler's `destroy` method is invoked. If you'd connected to resources in the `init` method, you might need to disconnect from them in the `destroy` method.

> The `init` method of `ClientHandler1` follows. It fetches the value of the property name, which was set in the `config.xml` file. (See The Client config.xml File.)

>     public void init(HandlerInfo info) {
>         handlerInfo = info;
>         name = (String) info.getHandlerConfig().get("name");
>         System.out.println("ClientHandler1: name = " + name);
>     }

> ##### The getHeaders Method of ClientHandler1

> The `getHeaders` method retrieves the header blocks of the message processed by this handler. Because `getHeaders` is declared as `abstract` in `GenericHandler`, it must be implemented in `ClientHandler1`:

>     public QName[] getHeaders() {
>         return handlerInfo.getHeaders();
>     }

> ##### The handleRequest Method of ClientHandler1

> A handler may process a SOAP request, response, or fault. Defined by the `Handler` interface, the `handleRequest`, `handleResponse`, and `handleFault` methods perform the actual processing of the SOAP messages. The `ClientHandler1` class implements the `handleRequest` method, listed at the end of this section.

> The `handleRequest` method of `ClientHandler1` gets access to the SOAP message from the `SOAPMessageContext` parameter. (For more information about the SOAP APIs, see Chapter 13.) The method adds two `SOAPHeaderElement` objects to the SOAP request: `loggerElement` and `nameElement`. The `loggerElement` header will be processed by `ServiceHandler1` and the `nameElement` header by `ServiceHandler2`. The `ServiceHandler1` instance will check the logging level that `ClientHandler1` set by invoking `loggerElement.setValue`. The `ServiceHandler2` instance will retrieve the `Duke` string from the header that `ClientHandler1` specified when calling `nameElement.addTextNode`.

> A handler is associated with a SOAP actor (role). If a header element is targeted at a specific actor and the header element has the `mustUnderderstand` attribute set to 1, and if a server request handler uses that actor, then the server handler must process the element. In this case, if the server handler of the targeted actor does not process the header, then a `MustUnderStandFault` will be thrown. If the server handler uses a different actor than the header element, then the `MustUnderStandFault` will not be thrown. All of the handlers in this example use the default actor "next." `ClientHandler1` adds header elements and invokes `setMustUnderstand(true)` on `loggerElement`. The `ServerHandler1` program will process `loggerElement` accordingly.

> Here is the `handleRequest` method of `ClientHandler1`:

>     public boolean handleRequest(MessageContext context) {
>         try {
>             SOAPMessageContext smc = (SOAPMessageContext) context;
>             SOAPMessage message = smc.getMessage();
>             SOAPPart soapPart = message.getSOAPPart();
>             SOAPEnvelope envelope = soapPart.getEnvelope();
>             SOAPHeader header = message.getSOAPHeader();
>             if (header == null) {
>                 header = envelope.addHeader();
>             }

>             System.out.println
>                 ("ClientHandler1: adding loggerElement");
>             SOAPHeaderElement loggerElement =
>                header.addHeaderElement
>                (envelope.createName("loginfo",
>                "ns1", "http://example.com/headerprops"));
>             loggerElement.setMustUnderstand(true);
>             loggerElement.setValue("10");

>             System.out.println
>                 ("ClientHandler1: adding nameElement");
>             SOAPHeaderElement nameElement =
>                 header.addHeaderElement
>                 (envelope.createName("clientname",
>                 "ns1", "http://example.com/headerprops"));
>             nameElement.addTextNode("Duke");

>         } catch (Exception e) {
>             throw new JAXRPCException(e);
>         }
>         return true;
>     }

> ##### The Client config.xml File

> The `ant` `build-client` task runs the `wscompile` command, which reads the `config.xml` file. Within this file, you declare handlers in `<handlerChains>`, an element that represents an ordered list of handlers. Because the client has only one handler, `<handlerChains>` contains a single `<handler>` subelement. The `runAt` attribute of the `<chain>` subelement specifies that this handler will run on the client side. The `className` attribute of the `<handler>` subelement identifies `client.ClientHandler1`. The optional `<property>` element assigns a name and value to a property that is passed to the handler instance in the `HandlerInfo` parameter of the `init` method. In `ClientHandler1`, the `init` method prints out the property value.

> The `config.xml` file follows:

>     <?xml version="1.0" encoding="UTF-8"?>
>     <configuration
>             xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">

>       <wsdl location="http://localhost:8080/handler/test?WSDL"
>              packageName="handlersample">
>         <handlerChains>
>           <chain runAt="client">
>             <handler className="client.ClientHandler1">
>                <property name="name" value="My Client Handler"/>
>             </handler>
>           </chain>
>         </handlerChains>

>       </wsdl>
>     </configuration>

> #### Server Handlers

> This example has two service handlers: `ServerHandler1` and `ServerHandler2`. The source code for these handlers is in the `examples/jaxrpc/advanced/handler/service/` subdirectory.

> ##### ServerHandler1

> This handler processes the SOAP request message that has been transmitted to the service endpoint.

> The `init` method of `ServerHandler1` fetches the value of the property `name`, which was set in the `jaxrpc-ri.xml` file. The `init` method follows:

>     public void init(HandlerInfo info) {
>         handlerInfo = info;
>         name = (String) info.getHandlerConfig().get("name");
>         System.out.println("ServerHandler1: name = " + name);
>     }

> The `handleRequest` method iterates through the header elements until it finds one with the element name `loginfo`. This element was added to the request message by the client handler. The `handleRequest` method must process the element and then detach (remove) it because of the following two reasons: First, the client handler invoked `setMustUnderstand(true)` on the element. Second, the server handler is using the actor ("next") targeted by the header element. Also, the `jaxrpc-ri.xml` file must declare that `ServerHandler1` understands this particular element. (See The Service jaxrpc-ri.xml File.) Without this declaration, a `MustUnderStandFault` will be thrown.

> To process the `loginfo` element, `handleRequest` invokes `getValue` and prints out a message if the log level is greater than 5. Because `ClientHandler1` set the level to 10, `handleRequest` prints the message.

> Here is the code for the `handleRequest` method of `ServerHandler1`:

>     public boolean handleRequest(MessageContext context) {
>         try {

>             SOAPMessageContext smc = (SOAPMessageContext) context;
>             SOAPMessage message = smc.getMessage();
>             SOAPHeader header = message.getSOAPHeader();

>             if (header != null) {
>                 Iterator iter = header.examineAllHeaderElements();
>                 while (iter.hasNext()) {
>                     SOAPElement element = (SOAPElement) iter.next();
>                     if
>     (element.getElementName().getLocalName().equals("loginfo")) {

>                         int logLevel =
>                            Integer.parseInt(element.getValue());
>                         if (logLevel > 5) {
>                             System.out.println
>                                ("ServerHandler1: important " +
>                                 "message (level " + logLevel + ")");
>                         } else {
>                             // message not important enough to log
>                         }
>                         element.detachNode();
>                         break;
>                    }
>                 }
>             }

>         } catch (Exception e) {
>             throw new JAXRPCException(e);
>         }

>         return true;
>     }

> ##### ServerHandler2

> After `ServerHandler1` finishes processing the SOAP request, `ServerHandler2` is invoked and processes the same request. Because both handlers are for the same service endpoint, they are packaged in the same WAR file and specified in the same `jaxrpc-ri.xml` file.

> To fetch the header blocks of the message, the `init` method of `ServerHandler2` invokes `info.getHeaders`, which returns a array of `QName` (qualified name) objects. Next, the `init` method gets the value of the `name` property, which was declared in the `jaxrpc-ri.xml` file. The `getHeaders` method of `ServerHandler2` returns an array of `QName` objects that represent the header blocks. Here is the code for the `init` and `getHeaders` methods:

>     public void init(HandlerInfo info) {
>         qnames = info.getHeaders();
>         name = (String) info.getHandlerConfig().get("name");
>         System.out.println("ServerHandler2: name = " + name);
>     }

>     public QName[] getHeaders() {
>         return qnames;
>     }

> The `handleRequest` methods of `ServerHandler1` and `ServerHandler2` began similarly. They both get the SOAP header from the `SOAPMessageContext` and then iterate the header elements until matching a name that was set by `ClientHandler1`. In `ServerHandler2`, the matching header element name is `clientname`. From this header element, `handleRequest` of `ServerHandler2` extracts and then prints the `String` that `ClientHandler1` passed to the `addTextNode` method. Here is a partial code listing of the `handleRequest` method of `ServerHandler2`:

>     . . .
>     if (header != null) {
>         Iterator iter = header.examineAllHeaderElements();
>         while (iter.hasNext()) {
>             SOAPElement element = (SOAPElement) iter.next();
>             if
>     (element.getElementName().getLocalName().equals("clientname"))
>             {
>                 String clientName = element.getValue();
>                 System.out.println
>                     ("ServerHandler2: Request is from " +
>                     clientName);
>             }
>      }
>     . . .

> ##### The Service jaxrpc-ri.xml File

> The `ant` `build` task compiles and packages the service files, including the handlers. During this task the `wsdeploy` command reads the j`axrpc-ri.xml` file to get information about the service.

> In `jaxrpc-ri.xml`, he `<chain>` subelement of `<handlerChains>` specifies server for the `runAt` attribute. Because the service endpoint has two handlers, the `<handlerChains>` element encloses two `<handler>` elements.

> The first `<handler>` element declares that `ServerHandler1` understands the `loginfo` header. This declaration is required because `ClientHandler1` invoked `setMustUnderstand(true)` on `loggerElement`. The attributes of the `ServerHandler1` `<handler>` element correspond to the parameters of the `envelope.createName` method invoked in `ClientHandler1`.

> The second `<handler>` element is for `ServerHandler2`. For requests, by default multiple handlers are invoked in the order in which they appear in the `<handlerChains>` element. For responses and faults, the handlers are invoked in the reverse order.

> Here is the `jaxrpc-ri.xml` file:

>     <?xml version="1.0" encoding="UTF-8" ?>
>     <webServices
>         xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd"
>         version="1.0"
>         targetNamespaceBase="http://com.test/wsdl"
>         typeNamespaceBase="http://com.test/types"
>         urlPatternBase="/test">

>         <endpoint
>             name="MyHandlerApp"
>             displayName="An application for testing handlers"
>             description="...description of app"
>             interface="service.HandlerTest"
>             implementation="service.HandlerTestImpl">

>         <handlerChains>
>           <chain runAt="server">
>             <handler className="service.ServerHandler1"
>                 headers="ns1:loginfo"
>                 xmlns:ns1="http://example.com/headerprops">
>               <property name="name" value="server1"/>
>             </handler>

>             <handler className="service.ServerHandler2">
>               <property name="name" value="server2"/>
>             </handler>
>           </chain>
>         </handlerChains>
>         </endpoint>

>         <endpointMapping
>             endpointName="MyHandlerApp"
>             urlPattern="/test"/>
>     </webServices>

> ### Advanced Static Stub Example

> This example demonstrates the following:

> - Creating a service and a static stub client that use doc/literal and are WS-I compliant.
> - Generating the wrapper classes required by literal.
> - Starting with a WSDL file, creating a service and a static stub client.
> - Making a one-way call from a static stub client to a WS-I compliant service.

> The files for this example are in the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/stubs/` directory.

> #### Building and Running the Advanced Static Example

> To build, deploy, and run this example, go to the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/stubs/` directory and type the following:

>     ant build
>     ant deploy
>     ant build-client
>     ant run

> The `run` task executes the `HelloClient` program, which should display the following lines:

>     Running echo String from a staticstub client.
>     Hi there Duke!!!

>     Running SimpleValueType from a staticstub client.
>     Echoing the boolean set in ValueType by server :false
>     Echoing the integer set in ValueType by server :54
>     Echoing the string set in ValueType by server  :Server Entry :
>     Test Data

>     Running the one way operation using ValuType from a staticstub
>     client

>     Running ComplexValuType from a staticstub client
>     Client output for testComplexValueType : 12345
>     Client output for testComplexValueType : 4.0
>     Client output for testComplexValueType : true

>     Original unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray : 129
>     Modified unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray  : 258

>     Running int[] from a staticstub client
>     Client output for testSimpleIntArray   : true

> #### Service Programming Model for the Advanced Static Stub Example

> With JWSDP, to create a JAX-RPC service you begin with either a service endpoint interface or a WSDL file. In the example described in Creating a Web Service with JAX-RPC, you started with a service endpoint interface. In this example, you'll start with a WSDL file before building the service.

> The steps that follow outline the programming model for creating a WS-I compliant service when starting with a WSDL file follow. Steps 2, 4, 5, and 6 are performed by subtasks of the `ant build-service` task.

> 1. Get the WSDL file.

> Typically, you'd create a WSDL file with a development tool. For this example, the `conf/HelloWorldService.wsdl` file has been provided for you.

> 2. Generate the service endpoint interface and the other server-side classes.

> ant task: `generate-server`

> This task runs `wscompile` with the `-import`, `-model`, and `-f:wsi` options. The `wscompile` tool stores the generated classes and corresponding source code in the `build/classes/server/` subdirectory.

> For more information, see the sections Generating WS-I Compliant Service Files with wscompile and Service Endpoint Interface Generated by wscompile.

> 3. Code the service implementation class.

> Located in the `src/server/` subdirectory, the `HelloImpl.java` code implements the service endpoint interface (`HelloIF`) generated in the preceding step. The `HelloImpl.java` file is included with the tutorial, so in this example you don't have to code it. If you did have write `HelloImpl.java`, you'd first examine the generated `HelloIF.java` code for the signatures of the methods that you need to implement.

> This approach might seem backwards, because with the help of an IDE such as SunONE Studio, you'd probably code the service implementation first and then generate the service endpoint interface and WSDL file. However, if you are developing a client for someone else's service, you might want to start with a WSDL to create a simple service for unit testing.

> 4. Compile the service implementation class.

> ant task: `compile-server-classes`

> 5. Create the raw WAR file.

> ant task: `create-raw-war`

> This step packages the server-side files into a raw WAR file. The term raw indicates that this WAR file is not ready for deployment. In this example, the raw WAR file resides in the `build/war/` subdirectory and is named `jaxrpc-DocumentLitHelloService-raw.war`.

> 6. Create a deployable (cooked) WAR file.

> ant task: `build-war`

> To cook the raw WAR file, you run the `wsdeploy` command. The cooked WAR file is named `jaxrpc-DocumentLitHelloService.war`. (For more information about `wsdeploy`, see the section process-war.)

> 7. Deploy the WAR file.

> ant task: `deploy`

> This action deploys the `HelloWorldService` at the following URL:

>     http://localhost:8080/jaxrpc-DoclitHelloService/hello

> #### Generating WS-I Compliant Service Files with wscompile

> Because the client and server in this example are WS-I compliant, `wscompile` is run with the `-f:wsi` option. The `ant` `generate-server` task runs `wscompile` as follows:

>     wscompile -keep -import
>               -model model-DocumentLitHelloService.xml.gz
>               -f:wsi conf/config-server.xml

> Table Table 12-1 describes these options.

> Table 12-2 wscompile Options for WS-I Compliance
> Option | Description
> --- | ---
> -keep | Keep all generated files, including the source files. These files reside in the build/classes/server/hello/ subdirectory.
> -import | Import the service description from the WSDL file listed in the configuration file (conf/config-server.xml) and then generate service interfaces and value types.
> -model | Write information about the internal data structures used by the service to a model file. The wsdeploy command gets information from the model file that it needs for generating runtime classes. The model file is implementation specific and is not portable.
> -f:wsi | Generate files for a WS-I compliant service or client.

> The `wscompile` command requires a configuration file. When you start with a WSDL file, the configuration file must have a `<wsdl>` element, which specifies the location of the WSDL file. Here is the listing for `conf/config-server.xml`, the configuration file used in this example:

>     <?xml version="1.0" encoding="UTF-8"?>
>     <configuration
>         xmlns="http://java.sun.com/xml/ns/jax-rpc/pi/config">
>         <wsdl
>             location="conf/HelloWorldService.wsdl"
>             packageName="hello" />
>     </configuration>

> #### Client Programming Model for the Advanced Static Stub Example

> When creating a client for a Web service, you usually begin with the WSDL file that's been made available by the service developers. The steps that follow briefly describe the process for creating WS-I compliant client when starting with a WSDL file. Note that steps 2 and 6 are subtasks of the ant `build-client` task.

> 1. Make sure that the service has been deployed.

> When you ran the `ant` `deploy` command, a WSDL file was deployed with the service. In the next step, the `wscompile` command that generates client files refers to the deployed WSDL file.

> 2. Generate service endpoint interface and client-side classes.

> ant task: `generate-client`

> This task runs `wscompile` with the `-gen:client` and `-f:wsi` options. The `wscompile` tool stores the generated classes and corresponding source code in the `build/classes/client/` subdirectory.

> For more information, see the sections Generating the Static Stub Client Files with wscompile and Service Endpoint Interface Generated by wscompile.

> 3. Identify the signatures of the remote methods.

> A remote client may call the methods defined in the service endpoint interface. To identify the method signatures, examine the source code of the interface, which was generated by `wscompile` in the previous step.

> 4. Identify the wrapper classes.

> For literal (not encoded) operations, the return types and parameters are within wrapper classes. When writing the client program, you'll need to know how to get and set the fields contained in the wrapper classes. Therefore, you'll need to examine the wrapper source code, also generated by `wscompile`. For an example, see the section Wrapper Classes for the sayHello Method.

> 5. Code the client program.

> Now that you're familiar with the remote method signatures and wrapper classes, you're ready to write the client code. In this example, the provided source code for the `HelloClient` program resides in the `src/client/` subdirectory.

> 6. Compile the client program and classes.

> ant task: `compile-client-classes`

> This task compiles the source code created in the previous step. After compilation, the client is ready to run.

> #### Generating the Static Stub Client Files with wscompile

> The `generate-client` task runs wscompile as follows:

>     wscompile -keep -gen:client -f:wsi conf/config-client.xml

> The `-keep` and `-f:wsi` options are described in Table 12-2. The `-gen:client` option instructs `wscompile` to generate files for a client.

> In the following listing of the configuration file (`conf/config-client.xml`), note that the `<wsdl>` element specifies the WSDL file that was deployed with the service.

>     <?xml version="1.0" encoding="UTF-8"?>
>     <configuration
>         xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
>         <wsdl location=
>         "http://localhost:8080/jaxrpc-DocumentLitHelloService/
>     hello?WSDL"
>             packageName="hello" />
>     </configuration>

> The `wscompile` tool generates class files required by the static stub client. The `HelloClient` program creates a stub as follows:

>     stub = (HelloIF_Stub)
>         (new HelloWorldService_Impl().getHelloIFPort());

> The `wscompile` tool generates the `HelloIF_Stub` and `HelloWorldService_Impl` classes and places them in the `build/classes/server/` subdirectory. To construct the `HelloIF_Stub` name, `wscompile` appends `_Stub` to the `portType` name defined in the WSDL file:

>     <portType name="HelloIF">

> To create the `HelloWorldService_Impl` name, `wscompile` appends `_Impl` to the service name, which the WSDL file specifies as follows:

>     <service name="HelloWorldService">

> #### Service Endpoint Interface Generated by wscompile

> The service endpoint interface defines the methods that a remote client can invoke. In this example, both invocations of `wscompile` generate a service endpoint interface named `HelloIF`:

>     package hello;

>     public interface HelloIF extends java.rmi.Remote {
>         public hello.ChangeComplexValueTypeResponse
>           changeComplexValueType(hello.ChangeComplexValueTyp
>            parameters) throws java.rmi.RemoteException;
>         public hello.ChangeValueTypeResponse
>             changeValueType(hello.ChangeValueType parameters)
>             throws java.rmi.RemoteException;
>         public hello.ReverseArrayResponse
>             reverseArray(hello.ReverseArray parameters)
>             throws java.rmi.RemoteException;
>         public hello.SayHelloResponse
>              sayHello(hello.SayHello parameters)
>              throws java.rmi.RemoteException;
>     }

> Note that `HelloIF.java`, as well as the source code for other generated files, is in the `build/classes/server/` and `build/classes/client` subdirectories.

> #### Wrapper Classes for the sayHello Method

> Because this example uses literal (not encoded), the parameters and return types of remote methods must be enclosed in wrapper classes. Because the client in this section is WS-I compliant, the `HelloIF` interface defines `sayHello` with the `SayHelloResponse` and `SayHello` wrapper classes:

>     public hello.SayHelloResponse
>         sayHello(hello.SayHello parameters)
>         throws java.rmi.RemoteException;

> The name of the wrapper class for the return type is the capitalized name of the method plus `Response`. For example, the `SayHelloResponse` class is the return type for the `sayHello` method. The `SayHelloResponse` class is a wrapper for a `String` variable, which can be accessed through a getter and a setter. The listing for `SayHelloResponse` follows.

>     package hello;

>     public class SayHelloResponse {
>         protected java.lang.String result;

>         public SayHelloResponse() {
>         }

>         public SayHelloResponse(java.lang.String result) {
>             this.result = result;
>         }

>         public java.lang.String getResult() {
>             return result;
>         }

>         public void setResult(java.lang.String result) {
>             this.result = result;
>         }
>     }

> The parameters for the remote call are wrapped in a single class, `SayHello`. The name of the class is the capitalized name of the method. In the listing `SayHello` that follows, note that it wraps two `String` parameters and provides a getter and setter for each `String`.

>     package hello;

>     public class SayHello {
>         protected java.lang.String string_1;
>         protected java.lang.String string_2;

>         public SayHello() {
>         }

>         public SayHello(java.lang.String string_1,
>            java.lang.String string_2) {
>             this.string_1 = string_1;
>             this.string_2 = string_2;
>         }

>         public java.lang.String getString_1() {
>             return string_1;
>         }

>         public void setString_1(java.lang.String string_1) {
>             this.string_1 = string_1;
>         }

>         public java.lang.String getString_2() {
>             return string_2;
>         }

>     public void setString_2(java.lang.String string_2) {
>             this.string_2 = string_2;
>         }
>     }

> When it invokes the `sayHello` method, the `HelloClient` program wraps the two `String` parameters in the `SayHello` class. To fetch the `String` returned by the method, the program invokes `getResult` on the `SayHelloResponse` wrapper class. The `HelloClient` program invokes `sayHello` as follows:

>     System.out.println(stub.sayHello(new SayHello
>         ("Hi there ", "Duke!!!")).getResult());

> #### Wrapper Classes for the reverseArray Method

> The `reverseArray` method accepts an `int` array and returns the array in reverse order. The service endpoint interface, `HelloIF`, defines `reverseArray` as follows:

>     public hello.ReverseArrayResponse
>         reverseArray(hello.ReverseArray parameters)
>         throws java.rmi.RemoteException;

> The `reverseArray` method uses three wrapper classes:

> - `IntArrayTest` - wrapper of an `int` array
> - `ReverseArray` - method parameter and wrapper of `IntArrayTest`
> - `ReverseArrayResponse` - method return type and wrapper of `IntArrayTest`

> The `ReverseArray` and `ReverseArrayResponse` classes contain the `IntArrayTest` class, which in turn contains an `int` array. In effect, the `int` array is wrapped twice.

> In the client, setting the method parameter requires two steps:

> 1. Setting the int array contained in `IntArrayTest`.
> 2. Setting the `IntArrayTest` in `ReverseArray`.

> Similarly, getting the method return value also requires two steps:

> 1. Getting the `IntArrayTest` from `ReverseArrayResponse`.
> 2. Getting the `int` array from `IntArrayTest`.

> The `HelloClient` program invokes `reverseArray` in the following code:

>     int[] intArray = {1,4,7,9,11};
>     IntArrayTest param = new IntArrayTest(intArray);
>     ReverseArrayResponse result1 =
>         stub.reverseArray(new ReverseArray(param));
>     IntArrayTest result = result1.getResult();
>     int[] rintArray = result.getIntArray();
>     System.out.println
>         ("\nRunning int[] from a staticstub client ");
>     System.out.println("Client output for testSimpleIntArray   : "
>          + java.util.Arrays.equals(intArray, rintArray));

> Generated by `wscompile`, the `IntArrayTest.java` file resides in the `build/classes/client/` subdirectory. In the `IntArrayTest` listing that follows, note that the `int` array field may be set either with a constructor or the `setIntArray` method.

>     package hello;

>     public class IntArrayTest {
>         protected int[] intArray;

>         public IntArrayTest() {
>         }

>         public IntArrayTest(int[] intArray) {
>             this.intArray = intArray;
>         }

>         public int[] getIntArray() {
>             return intArray;
>         }

>         public void setIntArray(int[] intArray) {
>             this.intArray = intArray;
>         }
>     }

> The `ReverseArray` parameter class wraps `IntArrayTest` provides a getter, setter, and constructors:

>     package hello;

>     public class ReverseArray {
>         protected hello.IntArrayTest intArrayTest_1;

>         public ReverseArray() {
>         }

>         public ReverseArray(hello.IntArrayTest intArrayTest_1) {
>             this.intArrayTest_1 = intArrayTest_1;
>         }

>         public hello.IntArrayTest getIntArrayTest_1() {
>             return intArrayTest_1;
>         }

>         public void setIntArrayTest_1(hello.IntArrayTest
>            intArrayTest_1) {
>             this.intArrayTest_1 = intArrayTest_1;
>         }
>     }

> Like the `ReverseArray` class, the `ReverseArrayResponse` class wraps `IntArrayTest`:

>     package hello;

>     public class ReverseArrayResponse {
>         protected hello.IntArrayTest result;

>         public ReverseArrayResponse() {
>         }

>         public ReverseArrayResponse(hello.IntArrayTest result) {
>             this.result = result;
>         }

>         public hello.IntArrayTest getResult() {
>             return result;
>         }

>         public void setResult(hello.IntArrayTest result) {
>             this.result = result;
>         }
>     }

> #### Wrapper Classes for the changeValueType Method

> A value type is a user-defined class with a state that may be passed as a method parameter or return type. A value type often represents a logical entity such as a customer or a purchase order. This example demonstrates the use of a class named `ValueType`, a user-defined class with a state that consists of three properties: a `boolean`, an `Integer`, and a `String`. Each of these properties has a getter and setter method.

> The `wscompile` tool generates the `ValueType` class and source code files, placing them in the `build/classes/server/` and `build/classes/client` subdirectories. Here is the source code for `ValueType`:

>     package hello;

>     public class ValueType {
>         protected boolean boolProperty;
>         protected java.lang.Integer integerProperty;
>         protected java.lang.String stringProperty;

>         public ValueType() {
>         }

>         public ValueType(boolean boolProperty, java.lang.Integer
>           integerProperty, java.lang.String stringProperty) {
>             this.boolProperty = boolProperty;
>             this.integerProperty = integerProperty;
>             this.stringProperty = stringProperty;
>         }

>         public boolean isBoolProperty() {
>             return boolProperty;
>         }

>         public void setBoolProperty(boolean boolProperty) {
>             this.boolProperty = boolProperty;
>         }

>         public java.lang.Integer getIntegerProperty() {
>             return integerProperty;
>         }

>         public void setIntegerProperty(java.lang.Integer
>            integerProperty) {
>             this.integerProperty = integerProperty;
>         }

>         public java.lang.String getStringProperty() {
>             return stringProperty;
>         }

>         public void setStringProperty(java.lang.String
>            stringProperty) {
>             this.stringProperty = stringProperty;
>         }
>     }

> The `changeValueType` method wraps `ValueType` in the `ChangeValueType` parameter and the `ChangeValueTypeResponse` return value. The service endpoint interface defines `changeValueType` as follows:

>     public hello.ChangeValueTypeResponse
>         changeValueType(hello.ChangeValueType parameters)
>         throws java.rmi.RemoteException;

> The following code listing shows how the `HelloImpl` class implements the `changeValueType` method. (The `HelloImpl.java` file is in the `src/server/` subdirectory.) The `changeValue` method extracts the `ValueType` parameter from the `ChangeValueType` wrapper class by invoking the `getValueType_1` method. Then the method alters the `ValueType` state by invoking the setter method for each property. Finally, the method returns the altered `ValueType` wrapped in a `ChangeValueTypeResponse`.

>     public ChangeValueTypeResponse changeValueType(ChangeValueType
>     evt) {

>         System.out.println("in echoValue type : " +
>             evt.getValueType_1());
>         ValueType vt = evt.getValueType_1();
>         String str = vt.getStringProperty();
>         vt.setStringProperty( "Server Entry : " + str);
>         vt.setIntegerProperty(new Integer(54));
>         vt.setBoolProperty(false);
>         return (new ChangeValueTypeResponse( vt ));
>     }

> The following code snippet shows how the `HelloClient` program invokes the `changeValueType` method.

>     ValueType vt = stub.changeValueType(new
>     ChangeValueType(valueType)).getResult();
>     System.out.println
>         ("Echoing the boolean set in ValueType by server :"
>         + vt.isBoolProperty());
>     System.out.println
>         ("Echoing the integer set in ValueType by server :"
>         + vt.getIntegerProperty().intValue());
>     System.out.println
>         ("Echoing the string set in ValueType by server  :"
>         + vt.getStringProperty());

> The `ChangeValueType` and `ChangeValueType` classes and source code reside in the `build/client/classes` and `build/server/classes` subdirectories. If you examine the source code, you can see the getter and setter methods that are invoked by the implementation class (`HelloImpl`) and client program (`HelloClient`).

> #### Wrapper Classes for the changeComplexValueType Method

> This method shows how to pass a value type that contains several simple types (such as `String` and `Calendar`), an `int` array, and another value type. The `HelloIF` interface defines `changeComplexValueType` as follows:

>     public hello.ChangeComplexValueTypeResponse
>          changeComplexValueType(hello.ChangeComplexValueType
>          parameters) throws java.rmi.RemoteException;

> `ChangeComplexValueTypeResponse` and `ChangeComplexValueType` are wrappers for `ValueTypeWObjectMemberAObjectMemberArray`, a complex type:

>     public class ValueTypeWObjectMemberAObjectMemberArray {
>         protected java.util.Calendar calender1;
>         protected java.util.Calendar calender2;
>         protected long longUnsignedInt;
>         protected hello.BaseFooObject myValueType;
>         protected hello.IntArrayTest simpleArray;
>         protected java.lang.String simpleString;
>     . . .

> `IntArrayTest` is a wrapper for an `int` array:

>     public class IntArrayTest {
>         protected int[] intArray;
>     . . .

> `BaseFooObject` is another value type:

>     public class BaseFooObject {
>         protected java.math.BigInteger first;
>         protected double second;
>         protected boolean third;
>     . . .

> In the `HelloClient` program, the `testComplexValueType` method invokes service's `changeComplexValueType` method. The `testComplexValueType` method creates a `ValueTypeWObjectMemberAObjectMemberArray` object and passes it as the parameter for `changeComplexValueType`. To extract the values in the `ChangeComplexValueTypeResponse` object returned by `changeComplexValueType`, the `testComplexValueType` method invokes several getter methods. Here is the source code for `testComplexValueType`:

>     public void testComplexValueType() throws Exception {
>         BaseFooObject baseFoo =
>            new BaseFooObject(new BigInteger("12345"), 04, true);
>         int[] intArray = {1,4,7,9,11};
>         IntArrayTest simpleArray = new IntArrayTest(intArray);

>         ValueTypeWObjectMemberAObjectMemberArray param =
>            new ValueTypeWObjectMemberAObjectMemberArray(
>            new java.util.GregorianCalendar(),
>            new java.util.GregorianCalendar(), 129, baseFoo,
>            simpleArray, "fooString");
>         ChangeComplexValueTypeResponse result1 =
>         stub.changeComplexValueType
>             (new ChangeComplexValueType(param));
>         ValueTypeWObjectMemberAObjectMemberArray result =
>             result1.getResult();
>         BaseFooObject rfoo = result.getMyValueType();

>         System.out.println
>         ("\nRunning ComplexValuType from a staticstub client ");
>         System.out.println
>         ("Client output for testComplexValueType : " +
>         rfoo.getFirst().toString());
>         System.out.println
>         ("Client output for testComplexValueType : " +
>         rfoo.getSecond());
>         System.out.println
>         ("Client output for testComplexValueType : " +
>         rfoo.isThird());

>         System.out.println
>         ("\nOriginal unsigned long in " + "
>         ValueTypeWObjectMemberAObjectMemberArray : 129");
>         System.out.println
>         ("Modified unsigned long in + " +
>         ValueTypeWObjectMemberAObjectMemberArray  : "
>         + result.getLongUnsignedInt());
>     }

> #### One-Way Invocations From a Static Stub

> Most remote calls use the synchronous request/response model. For example, when the `HelloClient` program calls the `sayHello` method, it waits until the method completes before resuming execution. At a lower level, on the client side the JAX-RPC implementation sends a SOAP request to the service and then waits. While the client is waiting, the service receives the request, processes it, and sends back a SOAP response. When the client receives the SOAP response it resumes execution. With the synchronous model, the client always waits for the response message, even if the return type of the method is `void`.

> In contrast, with the one-way model the client sends a SOAP request to the service and then continues execution upon receiving an HTTP response. However, the client does not wait for a SOAP response. The service processes the request but does not send back a SOAP response. Because the client does not receive a SOAP response, it does not know whether or not the service completed the remote call. This limitation might be acceptable for some applications, for example, a monitoring application that frequently checks the status of a system.

> ##### The One-Way Service

> To demonstrate the one-way model, in this example the `HelloClient` program invokes the `oneWayValueType` method on a separate service named `HelloWorldOneWayService`. This service was created along with `HelloWorldService` when you typed `ant` `build` and `ant` `deploy`. Although the two services share the same WAR file, `HelloWorldOneWayService` has a separate WSDL file (`HelloWorldOneWayService.wsdl`) and `wscompile` configuration files. The `wscompile` command-line options are the same for both services.

> In the programming model for this example, the WSDL file already exists before you run `wscompile` to generate the server-side files. If you were to start with a service endpoint interface, you would use the `-f:useonewayoperations` option of `wscompile` when generating the WSDL file.

> The `HelloWorldOneWayService` has the following endpoint address URL:

>     http://localhost:8080/jaxrpc-DoclitHelloService/oneway

> ##### The oneWayValueType Method

> The `HelloClient` invokes `oneWayValueType` in the following code:

>     . . .
>     onewayStub = (HelloOneWayIF_Stub)
>     (new HelloWorldOneWayService_Impl().getHelloOneWayIFPort());
>     valueType = new ValueType(true,new Integer(23),"Test Data");
>     . . .
>     onewayStub.oneWayValueType(new OneWayValueType(valueType));
>     . . .

> On the server side, `HelloOnewWayImpl` implements the method as follows:

>     package hello;

>     public class HelloOneWayImpl implements HelloOneWayIF {

>         public void oneWayValueType(OneWayValueType evt) {
>             ValueType vt = evt.getValueType_1();
>            System.out.println("OneWay boolean value from client :"
>                + vt.isBoolProperty());
>            System.out.println("OneWay integer value from client :"
>                + vt.getIntegerProperty().intValue());
>            System.out.println("OneWay string value from client : "
>                + vt.getStringProperty());
>         }
>     }

> The parameter of the method is `OneWayValueType`, a wrapper class for `ValueType`. The source code and class files, generated by `wscompile`, are in the `build/classes/client/` and `build/classes/server/` subdirectories.

> ### Advanced Dynamic Proxy Example

> This section shows how to build and run a dynamic proxy client that uses doc/literal and is WS-I compliant. If you are unfamiliar with dynamic proxies, you should first read the information in an earlier section, Dynamic Proxy Client Example.

> #### Building and Running the Advanced Dynamic Proxy Example

> Because this client invokes methods on the service described in the section Advanced Static Stub Example, you must deploy the service before proceeding. To build and run the dynamic proxy client, go to the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/dynamic/` directory and type the following:

>     ant build
>     ant run

> The `run` task executes the `ProxyHelloClient` program, which should display the following lines:

>     Running echo String from a dii client.
>     Response is:  Duke says: Java is Everywhere!

>     Running SimpleValueType from a dii client using WSDL

>     Original ValueType is:
>     Echoing the boolean set in ValueType by client :true
>     Echoing the integer set in ValueType by client :23
>     Echoing the string set in ValueType by client  :Test Data

>     The response from the Server is:
>     Echoing the boolean set in ValueType by server :false
>     Echoing the integer set in ValueType by server :54
>     Echoing the string set in ValueType by server  :Server Entry :
>     Test Data
>     Running ChangeComplexValueType from a dii client.

>     Running ComplexValuType from a dii client using WSDL
>     Client output for testComplexValueType : 12345
>     Client output for testComplexValueType : 4.0
>     Client output for testComplexValueType : true

>     Original unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray : 129
>     Modified unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray  : 258

>     Running int[] from a dii client using WSDL
>     Client output for testSimpleIntArray   : true

> #### Generating the Dynamic Proxy Client Files with wscompile

> This example has the same programming model as that described in the section Client Programming Model for the Advanced Static Stub Example. However, in this dynamic proxy example the `ant` `build` task executes the `generate-service-interface` subtask, which runs `wscompile` as follows:

>     wscompile -keep -import -f:wsi conf/config-client.xml

> This `wscompile` command generates the service endpoint interface and value types needed by the client. Generated wrapper classes are required because the client invokes operations that are literal (not encoded). For descriptions of the command options, see Table 12-1.

> The `wscompile` command reads the service description from the WSDL file specified by the `conf/config-client.xml` file:

>     <?xml version="1.0" encoding="UTF-8"?>
>     <configuration
>         xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
>         <wsdl
>             location="http://localhost:8080/jaxrpc-
>     DocumentLitHelloService/hello?WSDL"
>             packageName="hello" />
>     </configuration>

> The preceding `wscompile` command reads the same WSDL file as the command shown in the section Generating the Static Stub Client Files with wscompile. The two commands generate the same service endpoint interface and value types. For information about these generated files, see the section Service Endpoint Interface Generated by wscompile, as well as the subsequent sections on wrapper classes. Client developers should not write their own code as a substitute for the generated files. Instead, they should either rely on the files generated by `wscompile` or on files made available by the service developers.

> #### The ProxyHelloClient Code

> The source code for this client is in the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/dynamic/src/client/` directory.

> To set up the dynamic proxy, the `ProxyHelloClient` program performs these steps:

> 1. Sets program variables to match corresponding values in the WSDL file.

> `private static String BODY_NAMESPACE_VALUE =
> "http://hello.org/wsdl";
> String serviceName = "HelloWorldService";
> String portName = "HelloIFPort";`

> Table 12-3 identifies the XML elements in the WSDL file that match the preceding variables

> .

> Table 12-3 ProxyHelloClient Variables and Corresponding WSDL Elements
> Program Variable | WSDL Element
> --- | ---
> `BODY_NAMESPACE_VALUE` | `<definitions>`
> `serviceName` | `<service>`
> `portName` | `<port>`

> 2. Sets the endpoint URL that denotes the location of the WSDL file that is deployed with the service.

> `String UrlString =
> "http://localhost:8080/jaxrpc-DocumentLitHelloService/ hello?WSDL";`

> The endpoint address and the WSDL must be supplied by the service developer or deployer.

> 3. Creates the service.

> `URL helloWsdlUrl = new URL(UrlString);
> Service helloService =
> serviceFactory.createService(helloWsdlUrl,
> new QName(BODY_NAMESPACE_VALUE, serviceName));`

> The `createService` method invocation has two parameters: a `QName` (qualified name) representing the name of the service and a URL designating the location of the WSDL file. At runtime, the service will be configured with information fetched from the WSDL file.

> 4. Creates the dynamic proxy.

> `HelloIF proxy = null;
> ...
> proxy = (HelloIF) helloService.getPort(
> new QName(BODY_NAMESPACE_VALUE, portName),
> hello.HelloIF.class);`

> The `wscompile` tool generated `HelloIF.class`, the service endpoint interface. Because the client code refers to `HelloIF.class`, you must run `wscompile` before compiling the client.

> To invoke the `sayHello` method, the program does the following:

> 1. Instantiates the parameter of the remote call.

> `SayHello request = new SayHello(" Duke says: " +
> "Java is Everywhere!");`

> The `SayHello` and `SayHelloResponse` wrapper classes are also generated by `wscompile`.

> 2. Invokes `sayHello` on the dynamic proxy:

> `SayHelloResponse response = proxy.sayHello(request);`

> 3. Gets and prints the string returned by `sayHello`.

> `System.out.println("Response is: " + response.getResult());`

> ### Advanced DII Client Example

> This section demonstrates two DII clients:

> - `DIIHelloClient` - relies on the deployed WSDL during runtime
> - `DIINoWSDLHelloClient` - does not rely on a WSDL during runtime

> During development, `wscompile` reads the deployed WSDL and generates the value types needed by `DIIHelloClient` and `DIINoWSDLHelloClient`. Both clients use doc/literal, are WS-I compliant, and invoke methods on the service deployed in the section Advanced Static Stub Example. For an introduction to DII, see the section Dynamic Invocation Interface (DII) Client Example.

> #### Building and Running the Advanced DII Example

> To build the clients, go to the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/dii/` directory and type the following:

>     ant build

> To run `DIIHelloClient`, type:

>     ant run

> The `DIIHelloClient` program should display the following lines:

>     Running echo String from a dii client.
>     Response is:  Duke says: Java is Everywhere!

>     Running SimpleValueType from a dii client using WSDL

>     Original ValueType is:
>     Echoing the boolean set in ValueType by client :true
>     Echoing the integer set in ValueType by client :23
>     Echoing the string set in ValueType by client  :Test Data

>     The response from the Server is:
>     Echoing the boolean set in ValueType by server :false
>     Echoing the integer set in ValueType by server :54
>     Echoing the string set in ValueType by server  :Server Entry :
>     Test Data
>     Running ChangeComplexValueType from a dii client.

>     Running ComplexValuType from a dii client using WSDL
>     Client output for testComplexValueType : 12345
>     Client output for testComplexValueType : 4.0
>     Client output for testComplexValueType : true

>     Original unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray : 129
>     Modified unsigned long in
>     ValueTypeWObjectMemberAObjectMemberArray  : 258

>     Running int[] from a dii client using WSDL
>     Client output for testSimpleIntArray   : true

> To run `DIINoWSDLHelloClient`, type:

>     ant run-no-wsdl

> The `DIINoWSDLHelloClient` programs displays the same lines as `DIIHelloClient`, except for the following:

>     Running ComplexValueType from a dii client not using WSDL

> #### Generating the DII Client Files with wscompile

> The `ant` `build` task executes the `generate-service-interface` subtask, which runs this `wscompile` command:

>     wscompile -keep -import -f:wsi conf/config-client.xml

> The `wscompile` command and `config-client.xml` file of this example are identical to those used in Generating the Dynamic Proxy Client Files with wscompile. Unlike the dynamic proxy client, these DII clients do not need the service endpoint interface (`HelloIF`) generated by `wscompile`. However, like all clients that invoke operations that are literal (not encoded), the DII clients need the wrapper classes that `wscompile` generates. For information on wrapper classes, see the section Advanced Static Stub Example. Client developers should not write their own code as a substitute for the generated files.

> #### The DIIHelloClient Code

> At runtime, the `DIIHelloClient` program uses information in the deployed WSDL file to automatically configure the `Call` object on which it invokes remote methods. The items automatically configured include parameters, return types, and the target endpoint address.

> The source code for DIIHelloClient is in the `<INSTALL>``/jwstutorial12/examples/jaxrpc/advanced/dii/src/client/` directory.

> To set up the service, `DIIHelloClient` does the following:

> 1. Initializes program variables.

> `private static String BODY_NAMESPACE_VALUE =
> "http://hello.org/wsdl";
> private static String ENCODING_STYLE_PROPERTY =
> "javax.xml.rpc.encodingstyle.namespace.uri";`

> `String UrlString =
> "http://localhost:8080/jaxrpc-DocumentLitHelloService/hello?WSDL";`

> `String serviceName = "HelloWorldService";
> String portName = "HelloIFPort";
> Service service = null;
> QName port = null;`

> The `UrlString` object denotes the location of the WSDL file that will be accessed by the client at runtime. The WSDL file specifies the target endpoint address in the `<soap:address>` element. See Table 12-3 for more information on the WSDL elements that match the other initialized variables.

> 2. Creates the service.

> `service =
> factory.createService(new java.net.URL(UrlString),
> new QName(BODY_NAMESPACE_VALUE, serviceName));`

> Note that the first parameter of `createService` designates the URL of the WSDL file. At runtime, the service will be configured with information fetched from the WSDL.

> 3. Creates a `QName` object that represents the service port.

> `port = new QName(BODY_NAMESPACE_VALUE, portName);`

> To set up the `Call` object and make the remote invocation, `DIIHelloClient` performs these steps:

> 1. Creates the `Call` object.

> `QName operation = new QName("sayHello");
> Call call = service.createCall(port, operation);`

> In this step, the client creates a `Call` object for the port (`HelloIFPort`) and the remote method (`sayHello`). In a later step, the client will invoke the `sayHello` method on the `Call` object.

> 2. Sets properties on the `Call` object.

> `call.setProperty(Call.SOAPACTION_USE_PROPERTY
> new Boolean(true));
> call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
> call.setProperty(ENCODING_STYLE_PROPERTY, "");
> call.setProperty(Call.OPERATION_STYLE_PROPERTY,
> "document");`

> The previous two lines of code set the encoding/operation style to doc/literal. To learn more about these properties, refer to the SOAP and WSDL documents listed in Further Information.

> 3. Instantiates and loads the parameter request.

> `SayHello request = new SayHello(" Duke says: ",
> "Java is Everywhere!");
> Object[] params = {request};`

> `SayHello` is a wrapper class generated by `wscompile`.

> 4. Invokes the remote `sayHello` method.

> `SayHelloResponse response =
> (SayHelloResponse) call.invoke(params);`

> Like the `SayHello` parameter class, the `SayHelloResponse` class is generated by `wscompile`.

> 5. Gets and prints the string returned by `sayHello`.

> `System.out.println("Response is: " + response.getResult());`

> #### The DIINoWSDLHelloClient Code

> Unlike the `DIIWSDLHelloClient` program described in the preceding section, the `DIINoWSDLHelloClient` of this section does not configure the `Call` object at runtime with information retrieved from the WSDL file. Because `DIINoWSDLHelloClient` does not access the WSDL file, it must programatically configure the `Call` object with the following:

> - target endpoint address
> - operation
> - parameters
> - return type

> To prepare the service, the `DIINoWSDLHelloClient` program performs these steps:

> 1. Initializes program variables.

> `private static String BODY_NAMESPACE_VALUE =
> "http://hello.org/wsdl";
> private static String TYPE_NAMESPACE_VALUE =
> "http://hello.org/types";
> private static String ENCODING_STYLE_PROPERTY =
> "javax.xml.rpc.encodingstyle.namespace.uri";
> String UrlString =
> "http://localhost:8080/jaxrpc-DocumentLitHelloService/hello?WSDL";
> String serviceName = "HelloWorldService";
> String portName = "HelloIFPort";
> Service service = null;
> QName port = null;`

> `DIINoWSDLHelloClient` initializes these variables the same way as `DIIWSDLHelloClient`, with the exception of `UrlString`. In DIINoWSDLHelloClient, `UrlString` designates the target endpoint address, not the WSDL file location.

> 2. Creates the service.

> `ServiceFactory factory = ServiceFactory.newInstance();
> service = factory.createService(new QName(serviceName));`

> This `createService` method invocation does not include a parameter for the WSDL file.

> 3. Creates a `QName` object that represents the service port.

> `port = new QName(portName);`

> To configure the `Call` object and invoke the `sayHello` method, `DIINoWSDLHelloClient` does the following:

> 1. Creates the Call object.

> `QName operation =
> new QName(BODY_NAMESPACE_VALUE, "sayHello");
> Call call = service.createCall(port, operation);`

> 2. Sets the endpoint address of the target service.

> `call.setTargetEndpointAddress(endpoint);`

> In the WSDL file, the endpoint address is in the `<soap:address>` element.

> 3. Sets properties on the `Call` object.

> `call.setProperty(Call.SOAPACTION_USE_PROPERTY,
> new Boolean(true));
> call.setProperty(Call.SOAPACTION_URI_PROPERTY, "");
> call.setProperty(ENCODING_STYLE_PROPERTY, "");
> call.setProperty(Call.OPERATION_STYLE_PROPERTY,
> "document");`

> 4. Creates the `QName` object that names the request parameter.

> `QName REQUEST_QNAME =
> new QName(TYPE_NAMESPACE_VALUE, "sayHello");`

> The `TYPE_NAMESPACE_VALUE` string designates the namespace for the data types defined within the WSDL file. The WSDL file specifies the type information for `sayHello` under the `<types>` element, in the `<message>` element named `HelloIF_sayHello`.

> 5. Adds a parameter to the `Call` object.

> `call.addParameter("parameters", REQUEST_QNAME,
> hello.SayHello.class, ParameterMode.IN);`

> The `parameters` argument matches the name of the WSDL `<part>` subelement that is contained in the `<message>` element named `HelloIF_sayHello`. For DII clients that don't access the WSDL file at runtime, `addParameter` must specify the parameter class, in this case `hello.SayHello.class`.

> 6. Specifies the `QName` object for the call response.

> `QName RESPONSE_QNAME =
> new QName(TYPE_NAMESPACE_VALUE, "sayHelloResponse");`

> 7. Sets the return type on the `Call` object.

> `call.setReturnType(RESPONSE_QNAME,
> hello.SayHelloResponse.class);`

> Note that `setReturnType` specifies `SayHelloResponse.class` for the return type.

> 8. Instantiates and loads the parameter request.

> `SayHello request = new SayHello(" Duke says: ",
> "Java is Everywhere!");
> Object[] params = {request};`

> 9. Invokes the remote `sayHello` method.

> `SayHelloResponse response =
> (SayHelloResponse) call.invoke(params);`

> 10. Gets and prints the string returned by `sayHello`.

> `System.out.println("Response is: " + response.getResult());`

Download FAQ History |  | API Search Feedback

All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.