SCDJWS Study Guide: JAX-RPC
Printer-friendly version |
Mail this to a friend
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
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:
|
|
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:
- 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>
- 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();
}
}
}
- 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
- 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
- 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
- Create Client Code
- 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
- 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
- Creates a Service object
- Compile Client Code with Service Endpoint Interface class CLASSPATH
- 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:
- 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">
- Invoke createService() method of a ServiceFactory object
- 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">
- A Call object supports the dynamic invocation of the
remote procedures of a service
- 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);
- In the WSDL file, this address is specified by the
<soap:address> element
- Set properties on the Call object
- Properties to set
SOAPACTION_USE_PROPERTY
SOAPACTION_URI_PROPERTY
ENCODING_STYLE_PROPERTY
- Properties to set
- 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);
- Return type, method name, parameter
- 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);
- Assign the parameter value (Murphy) to a String array
(params) and then executes the invoke method with the String array as
an argument
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);