SCDJWS Study Guide: JAX-RPC


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

JAX-RPC Client-Side Programming Models

JAX-RPC Client Environment:

  • Service client programming model MUST be independent of how a service endpoint is implemented on the server side. A service client must invoke a service using the same client programming model irrespective of whether a service has been defined on the J2EE platform or even on a non-Java platform. In another words,  it allows JAX-RPC client to talk to another Web service deployed on a different platform and coded in a different language.
  • Service client environment should be capable of importing a WSDL document and generating a Java based client side representation for a service described in the WSDL document. A client side representation includes classes generated based on the mapping of the WSDL definitions to the corresponding Java representation.
  • Service client programming model MUST NOT be exposed or tied to a specific XML based protocol, transport or any JAX-RPC implementation specific mechanism. For  example, a JAX-RPC client should not be exposed to how a JAX-RPC client side runtime system invokes a remote method using a specific implementation level interaction mode and connection management.
  • Service client programming model can use either J2SE o J2EE programming model.

JAX-RPC defines three client-side programming models that Java application can be use to access Web service:

  • Generated stub: Both Interface (WSDL) and implementation (stub) are created at compile time
  • Dynamic proxies: Interface (WSDL) is created at compile time while implementation (dynamic proxy) created at runtime
  • Dynamic invocation interface (DII): Both interface (WSDL) and implementation are created at runtime

Generated stub and dynamic proxy methods use the Service Endpoint Interface (SEI). The SEI is basically the Java representation of the Web service operations described in the WSDL portType element. The SEI is a Java interface defining methods used by the Java client to interact with the Web service. The SEI is generated by a WSDL to Java mapping tool.

 

Generated stub  (Static stub)

Dynamic proxy

Dynamic Invocation Interface (DII)

Web service not expected to change

Some changes to the Web Service expected, such as the location of the service

Considerable changes to the Web service expected, such as:

  • Location of the service
  • Request/response format
  • Data types

Most common scenario

Less common

Less common

You can generate a stub class either from WSDL (using WSDL2Java) or from a service endpoint interface. A generated stub class is required to implement both javax.xml.rpc.Stub and the service endpoint interface. This stub interface provides APIs to configure stubs by setting properties like endpoint address, session, user name, password, etc.

The client at runtime creates dynamic proxy stubs using the javax.xml.rpc.Service interface. The client has a prior knowledge of the WSDL and the service it is going to invoke. It uses the javax.xml.rpc.ServiceFactory classes to create the service and get the proxy.

This software pattern eliminates the need for clients to know in advance a service's exact name and parameters. A DII client can discover this information at runtime using a service broker that can look up the service's information. This flexibility in service discovery enables the run-time system to use service brokers, which can adopt varying service discovery mechanisms - ebXML registries, UDDI, etc.

 


Generated Stub


The stub-based model generates local stub classes for the proxy from a WSDL document. When you change the WSDL document, you must regenerate the stubs. Web service vendors provides tools to generate and compile stubs. Along with the stubs, the tools generate additional classes, and a service definition interface (SDI), which is the interface that is derived from a WSDL's portType. This is the interface you use to access the operations on the Web service. The combination of these files are called client-side artifacts. Client-side artifacts are a collection of files on the client-side that handle communication between a client and a Web service. Generated client-side artifacts must include:

  • A stub class
  • A service endpoint interface
  • A service definition interface
  • An implementation of the service definition interface (the location class to help you find the endpoint)

The following is the interface of stub class define in package javax.xml.rpc:

package javax.xml.rpc;

import java.util.Iterator;

public interface Stub {

    /**
     * Standard property: User name for authentication.
     */
    public static final String USERNAME_PROPERTY = Call.USERNAME_PROPERTY;

    /**
     * Standard property: Password for authentication.
     */
    public static final String PASSWORD_PROPERTY = Call.PASSWORD_PROPERTY;

    /**
     * Standard property: Target service endpoint address. The
     * URI scheme for the endpoint address specification must
     * correspond to the protocol/transport binding for this
     * stub class.
     */
    public static final String ENDPOINT_ADDRESS_PROPERTY =
                       "javax.xml.rpc.service.endpoint.address";

    /**
     * Standard property: This boolean property is used by a service
     * client to indicate whether or not it wants to participate in
     * a session with a service endpoint. If this property is set to
     * true, the service client indicates that it wants the session
     * to be maintained. If set to false, the session is not maintained.
     * The default value for this property is false.
     */
    public static final String SESSION_MAINTAIN_PROPERTY = Call.SESSION_MAINTAIN_PROPERTY;

    public void _setProperty(String name, Object value);
    public Object _getProperty(String name);
    public Iterator _getPropertyNames();
}   

Let's summarize the Stub-based Invocation Model:

  • Stub class get generated from WSDL at compile time
  • All needed value classes are also generated
  • Instantiated using the Service class
  • Stub class is bound to a specific XML protocol (i.e., SOAP) and transport (i.e., HTTP)
  • Best performance
  • Stub class implements javax.xml.rpc.Stub interface and Service Definition interface.

Steps of coding and building a Static Stub Client:

  1. Generate Stubs
    • Run the wscompile command (in one line):

       wscompile -gen:client -d build -classpath build config-client.xml

    • Generates stub files based on the information it reads from the WSDL and config-client.xml files

       – The location of the WSDL is specified by the <wsdl> element of the config-client.xml file

       – –doption can be used to specify a directory where to place generated output files

    • A config-client.xml example:

    <configuration
        xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
       <wsdl location="build/Hello.wsdl" packageName="com.myco"/>
    </configuration>


  2. Create client code
    1). Creates a Stub object:

      (Stub)(new MyHelloService_Impl().getHelloIFPort())

    The code in this method is implementation-specific because it relies on a MyHelloService_Impl object, which is not defined in the specifications. The MyHelloService_Impl class will be generated by wscompile.


    2). Sets the endpoint address that the stub uses to access the service:

      stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, args[0]);

    At runtime, the endpoint address is passed to HelloClient in args[0] as a command-line parameter, which ant gets from the endpoint.address property in the build.properties file.


    3). Casts stub to the service endpoint interface, HelloIF:

      HelloIF hello = (HelloIF)stub;

    The following is a stand-alone Stub-based client example:

    package hello;
    import javax.xml.rpc.Stub;
    .........
    public class HelloClient {
        public static void main(String[] args) {
            try {
                Stub stub = (Stub)(new MyHelloService_Impl().getHelloIFPort());
                stub._setProperty (javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY, args[0]);
                HelloIF hello = (HelloIF)stub;
                System.out.println(hello.sayHello(args[1]));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    The following is a J2EE based Stub-based client using JNDI to lookup service:

    package hello;
    import javax.xml.rpc.Stub;
    ...
    public class HelloClient {
        public static void main(String[] args) {
            try {
                Context ic = new InitialContext();
                Service service = (Service) ic.lookup("java:comp/env/service/HelloService");
                HelloIF hello = (HelloIF) service.getHelloServiceProviderPort();
                System.out.println(hello.sayHello(args[1]));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

  3. Compile the client code with remote interface and stubs in CLASSPATH

    javac –classpath system_jars:dir_with_server_class_files:dir_with_stub_class_files HelloClient.java


  4. Package client classes and run the client code with JAX-RPC generated code and runtime system
    • Command to pack the client

    jar cvf hello_client.jar all_client_class_files:all_server_class_files

    • Command to run the client

    java –classpath hello_client.jar:jwsdp-jars hello.HelloClient

The step "Create client code" involves the Stub Configuration. The Stub instance must be configured XML protocol binding which is a compile time configuration and  service endpoint address which can be set at runtime. The stub configuration can be configured in two ways: Static configuration (Compile time) based on the WSDL description of a target service endpoint (such as wsdl:binding, soap:binding, wsdl:port) and Runtime configuration using the javax.xml.rpc.Stub API. The javax.xml.rpc.Stub provides few standard properties for Stub Configuration:


Standard Property
What is it?
R/O
javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY Target service endpoint address Required
javax.xml.rpc.Stub.PASSWORD_PROPERTY Password for authentication Required
javax.xml.rpc.Stub.USERNAME_PROPERTY User name for authentication Required
javax.xml.rpc.Stub.SESSION_MAINTAIN_PROPERTY This boolean property is used by a service client to indicate whether or not it wants to participate in a session with a service endpoint. Optioanl

Dynamic Proxy

The dynamic proxy client calls a remote procedure through a dynamic proxy stub, a class that is created during runtime by using JAX-RPC client APIs. Although the source code for the static stub client relied on an implementation-specific class, the code for the dynamic proxy client does not have this limitation. The client gets the service information from a given WSDL document. It uses the service factory class to create the service based on the WSDL document and obtains the proxy from the service.

The significant JAX-RPC client APIs used are:

  • javax.xml.rpc.rpc.Service
  • javax.xml.rpc.ServiceFactory

Let's summarize the Dynamic Proxy-based Invocation Model:

  • Stubs (Dynamic Proxy) are generated on the fly by JAX-RPC client runtime.
  • Application provides the service definition interface (WSDL) the dynamic proxy conforms to.
  • The created and casted dynamic proxy have over header. The performance slower than Stub-based invocation.
  • Does not depend on implementation specific class.
  • Portable client code because it does not depend on vendor generated service class before runtime.

Steps of coding and building Dynamic Proxy Client

  1. Generate Service Endpoint Interface Class
    • runs wscompile with the -import option
    • reads the wsdl file provided by the Web service and generates the service endpoint interface class

  2. Create Client Code
    1. Creates a Service object

      Service helloService = serviceFactory.createService(helloWsdlUrl,
                              new QName(nameSpaceUri, serviceName));

      • Service object is a factory for proxies
      • Service object itself is created from ServiceFactory object
      • Parameters of createService()
      • URL of the WSDL file
      • QName object

    2. Create a proxy with a type of the service endpoint interface

      dynamicproxy.HelloIF myProxy = (dynamicproxy.HelloIF)helloService.getPort(
                            new QName(nameSpaceUri,portName),
                            dynamicproxy.HelloIF.class);

      • HelloIF.class is generated by wscompile (at compile time)
      • The port name (HelloIFPort) is specified by the WSDL file
  3. Compile Client Code with Service Endpoint Interface class CLASSPATH
  4. Package Client to a jar file with SEI class.

The following is a sample of Dynamic Proxy Client code:

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

public class HelloClient {

    public static void main(String[] args) {
        try {

            String UrlString = args[0] + "?WSDL";
            String nameSpaceUri = "http://sample.proxy.org/wsdl";
            String serviceName = "MyHelloService";
            String portName = "HelloIFPort";
            URL helloWsdlUrl = new URL(UrlString)

            ServiceFactory serviceFactory = ServiceFactory.newInstance();
 
            //Create a Service using  the WSDL document
            Service helloService = serviceFactory.createService(helloWsdlUrl,
                        new QName(nameSpaceUri, serviceName));
  
           //Get the proxy by calling getPort method from an instance of Service. 
           dynamicproxy.HelloIF myProxy = (dynamicproxy.HelloIF) helloService.getPort(
                        new QName(nameSpaceUri, portName),
                        dynamicproxy.HelloIF.class);

            System.out.println(myProxy.sayHello(arg[1]));

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

Dynamic Invocation Interface

The Dynamic Invocation Interface (DII) client does not require a WSDL file to generate static stubs or pass the WSDL file to the service factory to create the service; instead, the client must know a service's address, operations, and parameters in advance. Using the Dynamic Invocation Interface (DII) enables the client to discover target services dynamically on runtime and then to invoke methods. During runtime, the client uses a set of service operations and parameters, establishes a search criterion to discover the target service, and then invokes its methods.This also enables a DII client to invoke a service and its methods without knowing its data types, objects, and its return types.

DII looks up a service, creates a javax.xml.rpc.Call object by setting the endpoint specific parameters and operations, and finally invokes the call object to execute the remote methods. The significant JAX-RPC client APIs used are:

  • javax.xml.rpc.Call
  • javax.xml.rpc.Service
  • javax.xml.rpc.ServiceFactory

Let's summarize the Dynamic Invocation Model:

  • Gives complete control to client developer
  • A client can call a remote procedure even if the signature of the remote prcedure or the name of the service are unknown until runtime
  • Does not require wscompile to create runtime classes
  • Most complex programming among the three invocation model
  • Enables broker model
    • Client finds (though some search criteria) and invokes a service during runtime through a broker. Could cobine with UDDI lookup and WSDL parsing for dynamic lookup and discovery
    • Used when service definition interface is  not known until runtime
    • Create JAX-RPC javax.xml.rpc.Call object and set operation and parameters during runtime

Steps of coding  DII Client:

  1. Create a Service object
    • Invoke createService() method of a ServiceFactory object

      Service service = factory.createService(new QName(qnameService));

    • qnameService parameter is the name of the service specified in WSDL

      <service name="MyHelloService">


  2. From the Service object, create a Call object
    • A Call object supports the dynamic invocation of the remote procedures of a service

      QName port = new QName(qnamePort);
      Call call = service.createCall(port);

    • The parameter of createCall is a QName object that represents the service endpoint interface, which is specified in WSDL

      <portType name="HelloIF">


  3. Set the service endpoint address on the Call object
    • In the WSDL file, this address is specified by the <soap:address> element

      call.setTargetEndpointAddress(endpoint);


  4. Set properties on the Call object
    • Properties to set

      SOAPACTION_USE_PROPERTY
      SOAPACTION_URI_PROPERTY
      ENCODING_STYLE_PROPERTY


  5. Sepcify the method's return type, name, and parameter
    • Return type, method name, parameter

      QName QNAME_TYPE_STRING = new QName(NS_XSD, "string");
      call.setReturnType(QNAME_TYPE_STRING);
      call.setOperationName(new QName(BODY_NAMESPACE_VALUE,"sayHello"));
      call.addParameter("String_1", QNAME_TYPE_STRING,ParameterMode.IN);


  6. Invoke the remote method on the Call object
    • Assign the parameter value (Murphy) to a String array (params) and then executes the invoke method with the String array as an argument

      String[] params = { "Murphy" };
      String result = (String)call.invoke(params);


The following is a sample of DII client:


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

public class HelloClient {
    private static String qnameService = "MyHelloService";
    private static String qnamePort = "HelloIF";
    private static String BODY_NAMESPACE_VALUE = "urn:Foo";
    private static String ENCODING_STYLE_PROPERTY ="javax.xml.rpc.encodingstyle.namespace.uri";
    private static String NS_XSD = "http://www.w3.org/2001/XMLSchema";
    private static String URI_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";

    public static void main(String[] args) {
        System.out.println("Endpoint address = " + args[0]);
        try {
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service =factory.createService(
                new QName(qnameService));
                QName port = new QName(qnamePort);
 
            //Create an instance of the Call object
            Call call = service.createCall(port);
 
            //Set service endpoint
            call.setTargetEndpointAddress(args[0]);
 
            //Configure your Call instance with its setter methods
            call.setProperty(Call.SOAPACTION_USE_PROPERTY,
                    new Boolean(true));
            call.setProperty(Call.SOAPACTION_URI_PROPERTY,"");
            call.setProperty(ENCODING_STYLE_PROPERTY,URI_ENCODING);
            //Set definition of the return Type
            QName QNAME_TYPE_STRING =new QName(NS_XSD, "string");
            call.setReturnType(QNAME_TYPE_STRING);
 
            //Set Name of the method to invoke 
            call.setOperationName(
                    new QName(BODY_NAMESPACE_VALUE,"sayHello"));
 
            //Set parameters defintions in the call object
            call.addParameter("String_1", QNAME_TYPE_STRING,
                    ParameterMode.IN);
            String[] params = { "Murph!" };
 
            //Finally invoke the method
            String result = (String)call.invoke(params);
            System.out.println(result);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

A DII client also can be invoked using one-way RPC mechanisms. In that case, the client does not require setting the return value types, and the call can be invoked as follows:

call.invokeOneWay(parameter);



Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |