Table of Contents
This chapter describes how to create and invoke various clients in order to use JAX-RPC web services.
Invoking a web service refers to the actions that a client application performs in order to use the web service. Client applications that invoke web services can be implemented by using any technology such as Java, Microsoft .NET, etc.
A Web service client is a program that makes service requests to the web service. Two types of web service clients can be created by using a JEUS JAX-RPC web service.
A stub client invokes a specific method of a local stub generated from the WSDL of a web service. The stub object is interoperable with remote web services.
This chapter shows how to create a web service client program that invokes the web service method called 'DocLitEchoService' that was created in "Chapter 21. Creating and Deploying JAX-RPC Web Services".
The wsdl2java Ant Task or wsdl2java command-line tool can be used to create a web service stub.
The following is the code in the build.xml file used for wsdl2java Ant Task.
[Example 22.1] << build.xml >>
... <target name="-pre-compile"> <antcall target="wsdl2java"> <param name="wsdl2java.option" value="-gen:client -d ${build.classes.dir} -package echo -compile -verbose ${src.conf}/DocLitEchoService.wsdl" /> </antcall> </target> ...
For more information about the wsdl2java task, refer to JEUS Reference Book. "4.10. wsdl2java".
Execute the following command to create the stub source code.
wsclient$ ant -pre-compile
When the previous command executes successfully, a web service stub source code is created. The stub source code is compiled under the directory that is specified in the <destDir> element of wsdl2java's build.xml file.
wsclient/build/classes/echo/ | +-- DocLitEchoService.java | +-- DocLitEchoService_Impl.java | +-- Echo.java | +-- ... </screen>
The following source files are generated from the example.
Class | Description |
---|---|
Echo.java | portType interface class |
Echo_Stub.java | Stub class of the portType interface class |
DocLitEchoService.java | Service interface class |
DocLitEchoService_Impl.java | Service implementation class |
*.java | Other classes |
The names of the generated Java file and the methods in the Java file are mapped from WSDL. The following are the mappings from WSDL to Java.
WSDL element | Mapping |
---|---|
<service> | Mapped to a service interface and implementation Java class. The interface file name is the
|
<port> | Mapped to a method in the service interface and
service implementation class The method's name is 'get' + <port> name. |
<portType> | Mapped to a Java interface and Java implementation class for the web service operations. This Java file name is the
|
This section shows how the four Java classes, created in the previous section, are used to create a web service client.
Web service object creation
The first step is to instantiate the web service implementation class for remote web services. The service implementation class in the example is called 'DocLitEchoService_Impl'.
The following Java code is an example of instantiating a web service object.
DocLitEchoService service = new DocLitEchoService_Impl();
Obtaining Port object from the Stub object
A port object must be obtained after the instantiation of web service implementation class.
The service interface class provides the necessary methods to obtain the port object. The name of the method is "get" + the name attribute value of WSDL's <port> element. The return value type is specified as WSDL's <portType> element value. WSDL port name is specified in the <port> element of WSDL document. The <port> element is a child element of the <service> element.
The following is the WSDL file for this example.
<wsdl:portType name=Echo”>
. . .
</wsdl:portType>
. . .
<wsdl:service name=”DocLitEchoService”>
<wsdl:port binding=”impl:EchoSoapBinding” name=”EchoPort”>
<soap:address location=”http://localhost:8088/DocLitEchoServi
ce/DocLitEchoService”/>
</wsdl:port>
</wsdl:service>
The following is a section from the 'DocLitEchoService.java' file, an SEI.
<package echo; public interface DocLitEchoService extends javax.xml.rpc.Service { public java.lang.String getEchoPortAddress(); public echo.Echo getEchoPort() throws javax.xml.rpc.ServiceException; }
The following is the source code for obtaining a port object from the service object.
DocLitEchoService service = new DocLitEchoService_Impl();
Echo port = service.getEchoPort();
Invoking a method on a Port Object
After obtaining a port object, remote web service operations can be executed by calling the methods of the port object. In the example, the web service port provides a method called 'echoString'.
The following is the code for executing the method.
DocLitEchoService service = new DocLitEchoService_Impl();
Echo port = service.getEchoPort();
String s = port.echoString(“JEUS”);
The method can also be execute with the following code.
Echo port = new DocLitEchoService_Impl().getEchoPort();
String s = port.echoString(“JEUS”);
The following is an example of implementing the web service client, assuming that it is running in the 'wsclient/src/j2se' directory.
[Example 22.2] <<ProxyClient.java>>
package j2se; import echo.DocLitEchoService_Impl; import echo.Echo; public class ProxyClient { public static void main(String args[]) { ProxyClient client = new ProxyClient(); client.run(); } public void run() { try { Echo port = new DocLitEchoService_Impl().getEchoPort(); String s = port.echoString("JEUS"); System.out.println("response = " + s); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } }
In order to compile the 'ProxyClient' code from the previous example, execute the following command from the 'wsclient' directory.
JEUS_HOME/samples/webservice/jaxrpc/from_java/doclit/doclit-client$ ant build
If the compilation is successful, the following compiled class file is created.
JEUS_HOME/samples/webservice/jaxrpc/from_java/doclit/doclit-client/build/classes/j2s e/ProxyClient.class
With a dynamic invocation interface (DII), a client can call a remote procedure even if the signature of the remote operation or the web service name are unknown until runtime.
This section describes how to create a DII client.
The JAX-RPC 1.1 API is used to create DII clients. The JEUS JAX-RPC web service fully supports the JAX-RPC 1.1 API. This section will illustrate a simple example of using the JAX-RPC API.
For more information about JAX-RPC, refer to the JAX-RPC specification (http://www.jcp.org/en/jsr/detail?id=101) and the JAX-RPC documentation on Oracle's website (http://www.oracle.com/technetwork/java/docs-142876.html).
Note that a DII client can only use the RPC-oriented web service invocation. The examples demonstrate how to write a DII client that invokes echoString operation of a RPC-oriented web service called 'RpcEncEchoService'.
To create a DII client:
Add the following code to the DII client code.
import javax.xml.rpc.Call; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; import javax.xml.rpc.ParameterMode; import javax.xml.namespaceQName;
Create the ServiceFactory and Service objects.
String targetNamespace = “urn:RpcEncService”; String serviceName = “RpcEncService”; ServiceFactory factory = ServiceFactory.newInstance(); Service service = factory.createService(new QName(targetNamespace, serviceName);
Define and create a Call object.
String operationName = “echoString”; QName QNAME_XSD_STRING = new QName(“http://www.w3.org/2001/XMLSchema”, “string”); Call call = (Call) service.createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName(new QName(targetNamespace, operationName)); call.addParameter("String_1", QNAME_XSD_STRING, ParameterMode.IN); call.setProperty(Call.OPERATION_STYLE_PROPERTY, "rpc"); call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY, "http://schemas.xmlsoap.org/soap/encoding/"); call.setReturnType(QNAME_XSD_STRING);
Invoke a web service operation by using the Call object.
String ret = (String)call.invoke(new Object[] { “JEUS” } );
The following is an example of creating a DII client, assuming that the client file is in the 'C:/wsclient/src' directory.
[Example 22.3] << DIIClient.java >>
package j2se; import javax.xml.namespace.QName; import javax.xml.rpc.Call; import javax.xml.rpc.ParameterMode; import javax.xml.rpc.Service; import javax.xml.rpc.ServiceFactory; public class DIIClient { private static final String NS_XSD = "http://www.w3.org/2001/XMLSchema"; private static final QName QNAME_XSD_STRING = new QName(NS_XSD, "string"); public void run() { try { ServiceFactory factory = ServiceFactory.newInstance(); String endpoint = "http://localhost:8088/" + "RpcEncEchoService/RpcEncEchoService"; String targetNamespace = "urn:RpcEncService"; Service service = factory.createService( new QName(targetNamespace, "RpcEncService")); Call call = service.createCall(); call.setTargetEndpointAddress(endpoint); call.setOperationName( new QName(targetNamespace, "echoString")); call.addParameter("String_1", QNAME_XSD_STRING, ParameterMode.IN); call.setProperty(Call.OPERATION_STYLE_PROPERTY, "rpc"); call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY, "http://schemas.xmlsoap.org/soap/encoding/"); call.setReturnType(QNAME_XSD_STRING); String ret = (String)call.invoke(new Object[] { "JEUS" }); System.out.println("response = " + ret); } catch (Exception e) { System.err.println(e.toString()); e.printStackTrace(); } } public static void main(String[] args) { DIIClient client = new DIIClient(); try { client.run(); } catch (Exception e) { e.printStackTrace(); } } }
In order to compile the DII client code, execute the following command from the 'wsclient' directory in the console.
JEUS_HOME/samples/webservice/jaxrpc/from_java/rpcenc/rpcenc-client$ ant build
If the compilation is successful, the following compiled class file is created.
JEUS_HOME/samples/webservice/jaxrpc/from_java/rpcenc/rpcenc-client/build/classes/j2s e/DIIClient.class
Invoking web services from EJB or Servlet that is deployed on a JEUS server is fundamentally identical to invoking it from a stand-alone client. However, the current Java EE web service specification defines a separate programming model to facilitate the portability of Java EE web service clients. It is recommended to follow the model for programming client applications.
From the web service client's point of view, a web service is a group of methods that execute business logic for the client. The client does not know whether those methods are invoked locally or remotely. The client invokes a web service by using an SEI (Service Endpoint Interface) that is defined in JAX-RPC specification.
Java EE clients use JNDI to access a service object that implements the service interface defined in the JAX-RPC. The service object is a factory that the client uses to obtain a proxy or stub that implements an SEI. A service Interface is either a javax.xml.rpc.Service interface defined in the JAX-RPC or a service interface that inherits it.
A client developer first obtains an SEI and service interface, which are generated according to WSDL→Java mapping rule defined in the JAX-RPC. Client developers are recommended not to create a stub at the time of development, but to use an interface instead. A stub will be automatically generated according to the client environment where the client modules are deployed. The logical name is used for JNDI lookup of web services, and this name is defined in the client deployment descriptor file.
The following are the basic procedures for Java EE client programming.
Obtain an SEI through JNDI Lookup.
The client application developer must define the JNDI name of the logical service, which will be used to reference the service, in the deployment descriptor. Although it is not required, it is recommended to define all logical service reference names under the JNDI Namespace's sub-context called service.
The container must bind the service interface implementation under the client's environment context (java:comp/env) by using the logical name of the service reference.
InitialContext jndiContext = new InitialContext(); Service service = (Service)jndiContext.lookup("java:comp/env/service/DocLitEchoService");
In the previous example, the service interface (javax.xml.rpc.Service), is declared in the <service-interface> element, which is a child element of the <service-ref> element in the web.xml file. In addition, a JNDI name is also declared in the <service-ref-name> element for binding the two.
In the JAX-RPC, a service can be instantiated from the ServiceFactory class. However, it is not recommended to use the ServiceFactory class in a Java EE client program. Java EE client should always obtain the service through JNDI lookup.
Instantiate a stub or a call object by using the service interface API.
Service interface is used when a client tries to instantiate a stub, and dynamic proxy or DII call object in order to access a service port. Client application developers must explicitly declare the service interface type, that will be used, in the client deployment descriptor file (web.xml).
The following is a sample web.xml file that declares the service interface type and JNDI name.
[Example 22.4] << web.xml >>
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<servlet>
<servlet-name>jsp_helloClient</servlet-name>
<jsp-file>/helloClient.jsp</jsp-file>
<load-on-startup>0</load-on-startup>
</servlet>
<service-ref>
<service-ref-name>
service/DocLitEchoService
</service-ref-name>
<service-interface>
javax.xml.rpc.Service
</service-interface>
<wsdl-file>
WEB-INF/wsdl/DocLitEchoService.wsdl
</wsdl-file>
<jaxrpc-mapping-file>
WEB-INF/DocLitEchoService-mapping.xml
</jaxrpc-mapping-file>
<port-component-ref>
<service-endpoint-interface>
echo.Echo
</service-endpoint-interface>
</port-component-ref>
</service-ref>
</web-app>
Invoke a web service through a stub or a call object.
Invocation through a stub object
A client can use the following service interface methods obtained through the service lookup to generate the stub and dynamic proxy.
java.rmi.Remote getPort(QName portName, Class serviceEndpointInterface) throws ServiceException; java.rmi.Remote getPort(java.lang.Class serviceEndpointInterface) throws ServiceException;
Invocation through a call object
A client can obtain a call object by using the DII method of the service interface that is obtained through JNDI lookup.
The following are the APIs used for dynamic port access
Call createCall() throws ServiceException; Call createCall()(QName portName) throws ServiceException; Call createCall(QName portName, String operationName) throws ServiceException; Call createCall(QName portName, QName operationName) throws ServiceException; Call[] getCalls(QName portName) throws ServiceException;
Java EE client creation is possible with or without the WSDL file. The client can be in a form of JSP, Servlet, or EJB, but it must be appropriate for the aforementioned programming model.
This section describes how to create Java EE clients in a form of JSP through an example.
Use the following procedures to invoke a service by using WSDL.
JEUS creates a Java EE portable client artifact and JAX-RPC mapping file by using the wsdl2java Ant Task and wsdl2java command-line tool. For more information about wsdl2java Ant Task, refer to JEUS Reference Book. "5.5.2. wsdl2java".
The following is an example of the build.xml file that uses Ant Task.
[Example 22.5] << build.xml >>
<target name="do-package-war"> ... <antcall target="wsdl2java"> <param name="wsdl2java.option" value="-import:client -d ${build.war.dir}/WEB-INF/classes -package echo -outputmapping ${build.war.dir}/WEB-INF/DocLitEchoService-mapping.xml -compile ${src.web}/WEB-INF/wsdl/DocLitEchoService.wsdl" /> </antcall> ... </target>
After executing the "ant build" command, Java EE portable client artifact and JAX-RPC mapping file will be created.
Create the client program.
When developing a client application with WSDL, the stub or call object can be obtained by using an interface method such as java.xml.rpc.Service.
java.rmi.Remote getPort(QName portName, Class serviceEndpointInterface) throws ServiceException; java.rmi.Remote getPort(java.lang.Class serviceEndpointInterface) throws ServiceException; Call createCall() throws ServiceException; Call createCall()(QName portName) throws ServiceException; Call createCall(QName portName, String operationName) throws ServiceException; Call createCall(QName portName, QName operationName) throws ServiceException; Call[] getCalls(QName portName) throws ServiceException;
The following is an example JavaEE client program in JSP that instantiates a dynamic proxy to invoke the web service.
[Example 22.6] << helloClient.jsp >>
<%@ page language="java" %>
<%@ page import="javax.naming.*" %>
<%@ page import="javax.rmi.*" %>
<%@ page import="java.rmi.RemoteException" %>
<%@ page import="java.util.*" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.xml.rpc.Service" %>
<%@ page import="echo.*" %>
<%@ page errorPage="/error.html" %>
<%! String msgToSend = "msg_sent_by_jspClient";
String ret=null;
String exceptionString="";
%>
<%
try {
InitialContext jndiContext = new InitialContext();
Service service = (Service)jndiContext.lookup(
"java:comp/env/service/DocLitEchoService");
java.rmi.Remote port = service.getPort(Echo.class);
Echo echoPort = (Echo)port;
ret = echoPort.echoString(msgToSend);
} catch (Exception e) {
exceptionString = e.toString();
e.printStackTrace();
}
%>
<%= "Result is "+ret+"......"
%>
Create the standard DD(web.xml) file.
[Example 22.7] << web.xml >>
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<servlet>
<servlet-name>jsp_helloClient</servlet-name>
<jsp-file>/helloClient.jsp</jsp-file>
<load-on-startup>0</load-on-startup>
</servlet>
<service-ref>
<service-ref-name>
service/DocLitEchoService
</service-ref-name>
<service-interface>
javax.xml.rpc.Service
</service-interface>
<wsdl-file>
WEB-INF/wsdl/DocLitEchoService.wsdl
</wsdl-file>
<jaxrpc-mapping-file>
WEB-INF/DocLitEchoService-mapping.xml
</jaxrpc-mapping-file>
<port-component-ref>
<service-endpoint-interface>
echo.Echo
</service-endpoint-interface>
</port-component-ref>
</service-ref>
</web-app>
Specify the service name, which a JSP client obtains
through the JNDI lookup, in the <service-ref-name> element
of the web.xml file. Service interface is specified as the
javax.xml.rpc.Service interface in the <service-interface>
element.
This interface is instantiated with the information from the WSDL file, which is set in the <wsdl-file> element, when the client is deployed to JEUS. The required Java package type information is obtained from the JAX-RPC mapping file specified in the <jaxrpc-mapping-file> element.
The following is the JEUS web deployment descriptor file (jeus-web-dd.xml) from the previous example.
[Example 22.8] << jeus-web-dd.xml >>
<?xml version="1.0" encoding="UTF-8"?>
<jeus-web-dd xmlns="http://www.tmaxsoft.com/xml/ns/jeus">
<service-ref>
<service-client>
<service-ref-name>
service/DocLitEchoService
</service-ref-name>
<port-info>
<wsdl-port xmlns:ns1="urn:DocLitService">
ns1:Echo
</wsdl-port>
<stub-property>
<name>
javax.xml.rpc.service.endpoint.address
</name>
<value>
http://localhost:8088/DocLitEchoService/DocLitEchoService
</value>
</stub-property>
</port-info>
</service-client>
</service-ref>
</jeus-web-dd>
WS-I, a standard organization, requires web services to define and follow a basic profile for web service interoperability purposes. The current basic profile 1.0 requires the WSDL to be accessible at all times.
However, when trying to access a service that does not follow the basic profile, WSDL may not be accessible all the time. In such cases, DII (Dynamic Invocation Interface) enables the call object to invoke web services regardless of the state of WSDL. For this, the details including the styles and names of the operations in WSDL must be provided to the call object.
If WSDL is not specified in the client deployment descriptor file, the client program developer can instantiate the call object through an SEI method, as shown in the following.
Call createCall() throws ServiceException;
The following is an example of Java EE client in JSP that invokes a web service by using a call object.
[Example 22.9] << helloClient.jsp >>
<%@ page language="java" %>
<%@ page import="javax.naming.*" %>
<%@ page import="javax.rmi.*" %>
<%@ page import="java.rmi.RemoteException" %>
<%@ page import="java.util.*" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.xml.rpc.Service" %>
<%@ page import="javax.xml.rpc.Call" %>
<%@ page import="javax.xml.namespace.QName" %>
<%@ page import="javax.xml.rpc.ParameterMode" %>
<%@ page errorPage="/error.html" %>
<%! String msgToSend = "msg_sent_by_jspClient";
String ret=null;
String exceptionString="";
%>
<%
try {
InitialContext jndiContext = new InitialContext();
Service service = (Service)jndiContext.lookup(
"java:comp/env/service/RpcEncEchoService");
String targetNamespace = "urn:RpcEncService";
QName operationName = new QName(targetNamespace,"echoString");
Call call = service.createCall();
call.setOperationName(operationName);
call.addParameter("String_1",
new QName("http://www.w3.org/2001/XMLSchema", "string"),ParameterMode.IN);
call.setProperty(Call.OPERATION_STYLE_PROPERTY, "rpc");
call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY,
"http://schemas.xmlsoap.org/soap/encoding/");
call.setReturnType(new QName("http://www.w3.org/2001/XMLSchema","string"));
call.setTargetEndpointAddress("http://localhost:8088/" +
"RpcEncEchoService/RpcEncEchoService");
ret = (String)call.invoke(new Object[]{msgToSend});
} catch (Exception e) {
exceptionString = e.toString();
e.printStackTrace();
}
%>
<%= "Result is "+ret+"......"
%>
As can be seen in the previous example, the operation name
and its parameters are added after the call object has been
instantiated. At this point, additional properties, such as the
operation and encoding styles, can be configured as in the
following.
call.setProperty(Call.OPERATION_STYLE_PROPERTY, “rpc”); call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY, “http://schemas.xmlsoap.org/soap/encoding/”);
The following is the deployment descriptor file (web.xml) of the previous example.
[Example 22.10] << web.xml >>
<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<servlet>
<servlet-name>jsp_helloClient</servlet-name>
<jsp-file>/helloClient.jsp</jsp-file>
<load-on-startup>0</load-on-startup>
</servlet>
<service-ref>
<service-ref-name>
service/DocLitEchoService2
</service-ref-name>
<service-interface>
javax.xml.rpc.Service
</service-interface>
</service-ref>
</web-app>
Specify the service name, which a JSP client obtains
through the JNDI lookup, in the <service-ref-name> element. The
service interface is specified as the javax.xml.rpc.Service interface
in the <service-interface> element. To invoke web services
without WSDL, the settings in the JAX-RPC mapping file specified in
the <jaxrpc-mapping-file> element cannot be used.
A Java EE web service client is a single Java EE component that follows its own packaging style.
The following figure shows how to package the JSP client.
WAR | +-- JSP Client | +-- WEB-INF | +-- web.xml (Servlet DD) | +-- jeus-web-dd.xml (JEUS Specific DD) | +-- Jax-rpc mapping file | +-- wsdl | +-- wsdl file | +-- classes | +-- Java class component (SEI, Service Interface..)
The previous example shows how to invoke a web service by deploying the packaged JavaEE client and then invoking the JSP.
If the paths for WSDL file and JAX-RPC mapping file are configured in the <wsdl-file> and <jax-rpc-mapping-file> elements of the webservices.xml file, they do not have to follow the previous structure.