Skip Headers

Oracle® Application Server Web Services Developer's Guide 10g Release 3 (10.1.3) B14434-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 14 Assembling a J2SE Web Service Client

This chapter provides information on developing a Web services client for the J2SE platform. This chapter has the following sections.

- Understanding J2SE Web Service Clients

- Writing Web Service Client Applications

- Tool Support for Assembling J2SE Web Service Clients

## Understanding J2SE Web Service Clients

The J2SE client, unlike the J2EE client, is responsible for much of the underlying work of looking up the service, and creating and maintaining the instances of classes that access the Web service. Since developers cannot rely on the container, they must create and manage their own services, and ensure the availability of all runtime environments needed to access the Web service.

The following sections describe static stub clients and Dynamic Invocation Interface (DII) clients.

- Using Static Stub Clients

- Using the Web Service Dynamic Invocation Interface

### Using Static Stub Clients

The WebServicesAssembler command `genProxy` generates static stubs from a supplied WSDL document. The generated stubs implement the `javax.xml.rpc.Stub` interface and a service endpoint interface. Additionally, the generated stubs are specifically bound to the HTTP transport and SOAP protocol. You can instantiate the generated stubs and invoke their methods directly to send requests to the associated Web service.

In addition, WebServicesAssembler generates a client utility class that demonstrates how a client leverages the static stubs to interact with a Web service. The name of the utility client class is <`WSDL_port_name`>`Client.java`. This class handles all steps necessary for creating a stub instance. You may want to instantiate the utility client and use it to invoke the remote service's operations.

Note: The client utility class file is regenerated every time WebServicesAssembler is executed, it is strongly recommended that you place your own code in a separate file. Otherwise, you will lose your changes.

### Using the Web Service Dynamic Invocation Interface

The JAX-RPC Dynamic Invocation Interface supports the invocation of a remote Web service operation even if the name of the service or the signature of the remote method is unknown prior to runtime.

Support for DII is provided through OC4J's implementation of the `javax.xml.rpc.Call` interface. The `javax.xml.rpc.Service` class acts as a factory for `Call` instances by using the overloaded `javax.xml.rpc.Service.createCall()` method. Once created, the various getters and setters that the `Call` interface provides are used to configure the port type, the operation name, the service endpoint address, and other attributes required for executing the remote method.

For examples of using DII clients to invoke Web services, see "Using Dynamic Invocation Interface to Invoke Web Services".

### Prerequisites

Before you begin, provide the following files and information.

- Supply the URI to the WSDL you want to employ to generate the client. This chapter uses the WSDL file described in "Sample WSDL File".

- Decide on the destination location for generated artifacts.

- Decide on a package name for the client files.

### How to Assemble a J2SE Web Service Client with a Static Stub

You can use WebServicesAssembler to create a J2SE Web service client using static stubs. To create the static stub, follow these steps.

1. Provide the URI to the WSDL, the name of the output directory, the package name, and the other information and files described in the Prerequisites section as input to the WebServicesAssembler `genProxy` command. For example:

       java -jar wsa.jar -genProxy
                         -output build/src/client/
                         -wsdl http://localhost:8888/hello/HelloService?WSDL
                         -packageName oracle.demo.hello

   This command generates the client proxies and stores them in `build/src/client`. The client application uses the stub to invoke operations on a remote service. For more information on the required and optional arguments to `genProxy`, see "genProxy".

2. Use the client utility class file created by `genProxy` as your application client, or use it as a template to write your own client code. The client utility class file is one of a number of files created by `genProxy`.

   You can also use the client utility class file to test your endpoint. Example 14-2, "HelloInterfacePortClient.java Listing", illustrates the client utility class file created in this example. For more information about this file, see "Writing Web Service Client Applications".

3. Compile the client files and put them in the classpath.

   List the appropriate JARs on the classpath before compiling the client. Table A-2, "Classpath Components for a Client Using a Client-Side Proxy" lists all of the JAR files that can possibly be used on the client classpath. As an alternative to listing individual JARs, you can include the client-side JAR, `wsclient_extended.jar` on the client classpath. This JAR file contains all the classes necessary to compile and run a Web service client. The classes are from the individual JAR files listed in Table A-2. See "Setting the Web Service Proxy Client Classpath" for more information on `wsclient_extended.jar` and the client classpath.

4. Run the J2SE client from the command line.

#### Ant Tasks for Generating a J2SE Web Service Client

The current release provides Ant tasks for Web services development. The following code sample shows how the WebServicesAssembler `genProxy` command can be rewritten as an Ant task.

    <oracle:genProxy
                wsdl="http://localhost:8888/hello/HelloService?WSDL"
                output="build/src/client"
                packageName="oracle.demo.hello"/>

#### Sample WSDL File

Example 14-1 contains a partial listing of the `HelloService.wsdl` used to generate the client. One of the files generated from this WSDL is the client utility class file listed in Example 14-2.

This partial listing illustrates a number of entries in the WSDL file that are employed in the generation of the client utility class file. For example:

- The name of the client utility class file, `HelloInterfacePortClient.java`, is derived from the value of the `<port name>` element.

- The operation name, `sayHello`, which appears under the `<portType>` element, becomes a method in the client utility class file.

- The parameter and data type belonging to `sayHello` is defined by the `complexType` defining the `sayHello` request:

      <complexType name="sayHello">
          <sequence>
                <element name="name" nillable="true" type="string"/>
          </sequence>
      </complexType>

The preceding elements appear in bold in the partial listing of `HelloService.wsdl`.

Example 14-1 WSDL Fragment, With Elements Used in the Client Utility Class File

    <definitions
        ...
      >
        <types>
            <schema targetNamespace="http://hello.demo.oracle/" ... xmlns="http://www.w3.org/2001/XMLSchema"
               ...
                <complexType name="sayHello">
                    <sequence>
                        <element name="name" nillable="true" type="string"/>
                    </sequence>
                </complexType>
                <complexType name="sayHelloResponse">
                    <sequence>
                        <element name="result" nillable="true" type="string"/>
                    </sequence>
                </complexType>
                <element name="sayHelloElement" type="tns:sayHello"/>
                <element name="sayHelloResponseElement" type="tns:sayHelloResponse"/>
            </schema>
        </types>
        <message name="HelloInterface_sayHelloResponse">
            <part name="parameters" element="tns:sayHelloResponseElement"/>
        </message>
        <message name="HelloInterface_sayHello">
            <part name="parameters" element="tns:sayHelloElement"/>
        </message>
        <portType name="HelloInterface">
            <operation name="sayHello">
                <input message="tns:HelloInterface_sayHello"/>
                <output message="tns:HelloInterface_sayHelloResponse"/>
            </operation>
        </portType>
        <binding name="HelloInterfacePortBinding" type="tns:HelloInterface">
            <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
            <operation name="sayHello">
                <soap:operation soapAction="http://hello.demo.oracle/:sayHello"/>
                <input>
                    <soap:body use="literal" parts="parameters"/>
                </input>
                <output>
                    <soap:body use="literal" parts="parameters"/>
                </output>
            </operation>
        </binding>
        <service name="HelloService">
            <port name="HelloInterfacePort" binding="tns:HelloInterfacePortBinding">
                <soap:address location="HelloService"/>
            </port>
        </service>
    </definitions>

## Writing Web Service Client Applications

The `genProxy` command generates a client utility class file that enables you to invoke Web service methods. You can use this file as your application client, or use it as a template to write your own application client code.

Note: The client utility class file is regenerated each time you run `genProxy`. If you add code to this file for testing purposes, then your changes will be lost if you regenerate the proxy. For production code, your client code should exist outside of this utility class.

The command derives the name of the file by appending the suffix `Client` to the port name. For example, for the `HelloInterfacePort` port name, `genProxy` generates the `HelloInterfacePortClient.java` file. Example 14-2, "HelloInterfacePortClient.java Listing" illustrates the sample client utility class file generated by `genProxy`.

The client utility class serves as a proxy to the Web service implementation. The client-side proxy code constructs a SOAP request and marshals and unmarshals parameters for you. Using the proxy classes saves you the work of creating SOAP requests and data marshalling for accessing a Web service or processing Web service responses.

The most important part of the client utility class file is the factory code for creating `javax.xml.rpc.Service` objects and obtaining the operations available on the service. The `Service` object acts as an instance of the generated stub class.

Note the following lines of code in the client utility class file:

    public HelloInterfaceClient() throws Exception {
        ServiceFactory factory = ServiceFactory.newInstance();
        _port = ((HelloService)factory.loadService
                     (HelloService.class)).getHelloInterfacePort();
    }

If you write your own application client, you must supply this code. The following steps describe the code.

1. Instantiate a new `javax.xml.rpc.ServiceFactory` instance or use an existing instance.

       ServiceFactory factory = ServiceFactory.newInstance();

2. Load the service for a particular service endpoint interface using the `loadService` method. This returns an object of type `Service` that also implements the requested service endpoint interface.

       (HelloService)factory.loadService(HelloService.class)

   In this example, the returned `Service` is cast to the service endpoint interface `HelloService`.

3. Use the `get`...`()` method to get the desired port. The ellipsis ("...") represents the value of the `port name` element in the WSDL.

       HelloService.getHelloInterfacePort();

   In this example, the method name is `getHelloInterfacePort()`, where `HelloInterfacePort` is the `port name` in the WSDL. The method returns a Java implementation for `HelloInterfacePort`.

Example 14-2 displays the client utility class file, `HelloInterfacePortClient.java`, which was generated from the `HelloService.wsdl` in Example 14-1 by the `genProxy` command. The lines of code that create the `Service` objects and obtain the operations available on the service appear in bold.

Also note the presence of the `SESSION_MAINTAIN_PROPERTY` in this example. This property is used to alert the client that the Web service is stateful. You will want to maintain the session when the client is operating in conjunction with a server side, stateful Web service. By maintaining the session, subsequent requests to the service are faster.

Example 14-2 HelloInterfacePortClient.java Listing

    import oracle.webservices.transport.ClientTransport;
    import oracle.webservices.OracleStub;
    import javax.xml.rpc.ServiceFactory;
    import javax.xml.rpc.Stub;

    public class HelloInterfacePortClient {
        private HelloInterface _port;

        public HelloInterfacePortClient() throws Exception {
            ServiceFactory factory = ServiceFactory.newInstance();
            _port =((HelloService)factory.loadService(
               HelloService.class)).getHelloInterfacePort();
        }

        /**
         * @param args
         */
        public static void main(String[] args) {
            try {
                HelloInterfacePortClient myPort = new HelloInterfacePortClient();
                System.out.println("calling " + myPort.getEndpoint());
                // Add your own code here

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        /**
         * delegate all operations to the underlying implementation class.
         */
        // sayHello
        public String sayHello(String name) throws java.rmi.RemoteException {
            return _port.sayHello(name);
        }

        /**
         * used to access the JAX-RPC level APIs
         * returns the interface of the port instance
         */
        public oracle.demo.hello.HelloInterface getPort() {
            return _port;
        }

        public String getEndpoint() {
            return (String) ((Stub)
    _port)._getProperty(Stub.ENDPOINT_ADDRESS_PROPERTY);
        }

        public void setEndpoint(String endpoint) {
            ((Stub) _port)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,
    endpoint);
        }

        public String getPassword() {
            return (String) ((Stub) _port)._getProperty(Stub.PASSWORD_PROPERTY);
        }

        public void setPassword(String password) {
            ((Stub) _port)._setProperty(Stub.PASSWORD_PROPERTY, password);
        }

        public String getUsername() {
            return (String) ((Stub) _port)._getProperty(Stub.USERNAME_PROPERTY);
        }

        public void setUsername(String username) {
            ((Stub) _port)._setProperty(Stub.USERNAME_PROPERTY, username);
        }

        public void setMaintainSession(boolean maintainSession) {
            ((Stub) _port)._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, new
    Boolean(maintainSession));
        }

        public boolean getMaintainSession() {
            return ((Boolean) ((Stub)
    _port)._getProperty(Stub.SESSION_MAINTAIN_PROPERTY)).booleanValue();
        }

       /**
         * returns the transport context
         */
        public ClientTransport getClientTransport() {
            return ((OracleStub) _port).getClientTransport();
        }
    }

### Enabling Chunked Data Transfer for HTTP 1.1

OracleAS Web Services permits the chunked transfer encoding of messages when the protocol is HTTP 1.1. Chunked data transfer can be invoked on J2SE stub, J2EE stub and DII Web service clients.

For more information on how to enable this feature, see "Enabling Chunked Data Transfer for HTTP 1.1".

### Setting a Character Encoding for a SOAP Message on a J2SE Client

By default, a client assembled under Oracle Application Server Web Services sends a request message with a SOAP envelope encoded with UTF-8 characters. To override this behavior, you can set the following Oracle proprietary property:

    oracle.webservices.ClientConstants.CHARACTER_SET_ENCODING

This property can be used to set the character encoding for a J2SE client or a J2EE client. For more information on how to use this property, see "Setting a Character Encoding for a SOAP Message".

### Setting Cookies in a Client Stub

A client stub can be used to set the cookies used in an HTTP request.

To do this, follow these general steps:

1. Construct a cookie, using the `Cookie` class from the Oracle Applications Server 10g `HTTPClient` package.

   The `Cookie` class represents an HTTP cookie. `Cookie` has the following constructor:

   `Cookie (java.lang.String` `name`, `java.lang.String` `value`, `java.lang.String` `domain``,` `java.lang.String` `path`, `java.util.Date` `expires`, `boolean` `secure``)`

   All parameters except `expires` are required to the `Cookie` constructor.

2. Set the property `oracle.webservices.ClientConstants.COOKIE_MAP`.

   The value of the property is a `java.util.Map` object that contains items and keys of type `HTTPClient.Cookie`.

3. Set the `javax.xml.rpc.session.SESSION_MAINTAIN_PROPERTY` runtime property set to `true`.

   This property alerts the client that the Web service is stateful. If this property is not set to `true`, then the cookies will be ignored.

Example 14-3 illustrates stub code that sets the value of two cookies. The `cookieMap` variable is declared to be of type `java.util.Map` and obtains its contents from a `HashMap`. The `Cookie` constructor is used to define two cookies, `cookie` and `cookie2`. The `cookieMap.put` lines add the cookies to the hashmap. The `Stub.SESSION_MAINTAIN_PROPERTY` is present and set to `true` and the `ClientConstants.COOKIE_MAP` is set to `cookieMap`.

Example 14-3 Setting a Cookie in a Client Stub

    import HTTPClient.Cookie;
       Map cookieMap = new HashMap();

       Cookie cookie = new Cookie("name", "value", "oracle.com", "/",  null, false);
       Cookie cookie2 = new Cookie("name2", "value2", "oracle.com", "/", null, false);
       cookieMap.put(cookie, cookie);
       cookieMap.put(cookie2, cookie2);

       ((Stub) port)._setProperty(ClientConstants.COOKIE_MAP, cookieMap);
       ((Stub) port)._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
    ...

## Tool Support for Assembling J2SE Web Service Clients

Oracle JDeveloper enables you to build client applications that use Web services. It supports OC4J J2SE Web service clients by allowing you to create Java stubs from Web service WSDL descriptions. You can use these stubs to access existing Web services. For more information, see the JDeveloper on-line help.

## Additional Information

For more information on:

- assembling Web services from a WSDL, see Chapter 5, "Assembling a Web Service from a WSDL".

- assembling stateful Web services, see Chapter 6, "Assembling a Web Service with Java Classes".

- assembling Web services from EJBs, see Chapter 7, "Assembling a Web Service with EJBs".

- assembling Web services from a JMS queue or topic, see Chapter 8, "Assembling Web Services with JMS Destinations".

- assembling Web services from database resources, see Chapter 9, "Developing Database Web Services".

- assembling Web services with J2SE 5.0 Annotations, see Chapter 10, "Assembling Web Services with Annotations".

- building J2EE clients, see Chapter 13, "Assembling a J2EE Web Service Client".

- improving performance by data chunking, see "Enabling Chunked Data Transfer for HTTP 1.1".

- using the WebServicesAssembler tool to assemble Web services, see Chapter 17, "Using WebServicesAssembler".

- packaging and deploying Web services, see Chapter 18, "Packaging and Deploying Web Services".

- JAR files that are needed to assemble a client, see Appendix A, "Web Service Client APIs and JARs".

- Web services interoperability, see "Ensuring interoperable Web Services" in the Oracle Application Server Advanced Web Services Developer's Guide.

- using quality of service features in Web service clients, see "Managing Web Services" in the Oracle Application Server Advanced Web Services Developer's Guide.

- adding security to a Web service, see the Oracle Application Server Web Services Security Guide.

- how to write clients to access Web services secured on the transport level, see "Adding Transport-level Security for Web Services Based on EJBs" and "Accessing Web Services Secured on the Transport Level" in the Oracle Application Server Web Services Security Guide.

- adding reliability to a Web service, see "Ensuring Web Service Reliability" in the Oracle Application Server Advanced Web Services Developer's Guide.

- adding an auditing and logging configuration to a Web service, see "Auditing and Logging Messages" in the Oracle Application Server Advanced Web Services Developer's Guide.

- processing nonstandard data types, see "Custom Serialization of Java Value Types" in the Oracle Application Server Advanced Web Services Developer's Guide.

- the JAX-RPC mapping file, see "JAX-RPC Mapping File Descriptor" in the Oracle Application Server Advanced Web Services Developer's Guide.

- data types supported by OracleAS Web Services, see "Mapping Java Types to XML and WSDL Types" in the Oracle Application Server Advanced Web Services Developer's Guide.

- JDeveloper tool support for Web service development, see the JDeveloper on-line help.