Skip Headers
Oracle® Application Server Web Services Developer's Guide
10g Release 3 (10.1.3)
B14434-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
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

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

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: