||Struts 1.x 2.x | Spring | Strips | Wicket | Tapestry | Seam | JSF | RIFE | DWR | DOJO | EXT | Jquery | Json | Prototype | Hibernate | iBatis | web 2.0 | www.siva2baba.com & shivababa@gmail.com
   
  FrameWorks Theater
  Java Web Services Developer Pack with SOAP
 

Creating Web Services

Building an XML-RPC style web service using the J2EE 1.4 platform involves five steps:

  1. Design and code the web service endpoint interface.
  2. Implement the interface.
  3. Write a configuration file.
  4. Generate the necessary files.
  5. Use the deploytool to package the service in a WAR file and deploy it.

1. Design and Code the Service Endpoint Interface

The first step in creating a web service is to design and code its endpoint interface, in which you declare the methods that a web service remote client may invoke on the service. When developing such an interface, ensure that:

  • It extends the java.rmi.Remote interface
  • It does not have constant declarations such as public static final
  • Its methods throw the java.rmi.RemoteException (or one of its subclasses)
  • Its method parameters and return data types are supported JAX-RPC types

To get started, create a directory of your choice. For the following example, I created an apps directory under c:sunAppServer and a subdirectory of apps called build. The apps directory contains the .java files, and the build directory contains the .class, as well as other files that will be automatically generated.

The web service I will be developing for the rest of this article provides a summation service for adding two numbers. Nothing fancy, but as you will see, it will demonstrate how to develop, deploy, and use web services. Code Sample 1 shows the service endpoint interface, which is a regular Java language interface that extends the java.rmi.Remote interface. The MathFace interface declares one method, add, which takes two integer values and returns an integer value representing the sum of the two integer parameters:

Code Sample 1: MathFace.java

package math;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface MathFace extends Remote {
public int add(int a, int b) throws RemoteException;
}

2. Implement the Service Endpoint Interface

The next step is to implement the MathFace interface defined in Code Sample 1, which is quite straightforward, as shown in Code Sample 2.

Code Sample 2: MathImpl.java

package math;

import java.rmi.RemoteException;

public class MathImpl implements MathFace {
public int add(int a, int b) throws RemoteException {
return a + b;
}
}

Now, compile the .java files specifying the .class files to be written to the build directory created above. The -d option instructs the compiler to write the output .class files into the build directory:

prompt> javac -d build Math*.java

3. Write a Configuration File

The next step is to define a configuration file to be passed to the wscompile tool. Here I call the file config.xml (and save it under the apps directory). In this configuration file, I describe the name of the service, its namespace, the package name (math in this case) and the name of the interface (MathFace). Code Sample 3 shows the configuration file:

Code Sample 3: config.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<service
name="MyFirstService"
targetNamespace="urn:Foo"
typeNamespace="urn:Foo"
packageName="math">
<interface name="math.MathFace"/>
</service>
</configuration>

This file tells wscompile to create a WSDL file with the following information:

  • The service name is MyFirstService.
  • The WSDL namespace is urn:Foo.
  • The classes for the service are in the math package under the build directory.
  • The service endpoint interface is math.MathFace.

4. Generate the Necessary Mapping Files

Now, use the wscompile tool to generate the necessary files. Consider the following command executed from the apps directory:

prompt> wscompile -define -mapping build/mapping.xml -d build -nd build -classpath build config.xml

This command, which reads the config.xml file created earlier, creates the MyFirstService.wsdl file and mapping.xml in the build directory. The command line options or flags are:

  • -define: instructs the tool to read the service endpoint interface and create a WSDL file.
  • -mapping: specifies the mapping file and where it should be written.
  • -d and -nd: specifies where to place generated output files and non-class output files, respectively.

Believe it or not, you have now built a web service that is ready to be packaged and deployed.

The WSDL file MyFirstService.wsdl, generated by the wscompile tool, is shown in Code Sample 4. This file provides an XML description (based on WSDL) of the service that clients can invoke. To understand the details of the file you need some knowledge of WSDL -- but you don't need to understand all the details, so don't worry if you have no knowledge of WSDL.

Code Sample 4: MyFirstService.wsdl

<?xml version="1.0" encoding="UTF-8"?>

<definitions name="MyFirstService" targetNamespace="urn:Foo" xmlns:tns="urn:Foo"
xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<types/>
<message name="MathFace_add">
<part name="int_1" type="xsd:int"/>
<part name="int_2" type="xsd:int"/></message>
<message name="MathFace_addResponse">
<part name="result" type="xsd:int"/></message>
<portType name="MathFace">
<operation name="add" parameterOrder="int_1 int_2">
<input message="tns:MathFace_add"/>
<output message="tns:MathFace_addResponse"/></operation></portType>
<binding name="MathFaceBinding" type="tns:MathFace">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
<operation name="add">
<soap:operation soapAction=""/>
<input>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
use="encoded" namespace="urn:Foo"/>
</input>
<output>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
use="encoded" namespace="urn:Foo"/>
</output>
</operation></binding>
<service name="MyFirstService">
<port name="MathFacePort" binding="tns:MathFaceBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>

The mapping file, mapping.xml, generated by the wscompile tool is shown in Figure 5. This file follows the JSR 109 standard for Java <-> WSDL mappings. As you can see, the structure of the JAX-RPC mapping file matches closely with the structure of a WSDL file -- note the relationship between Java packages and XML namespaces. Each service offered is represented as a service-interface-mapping element. This element contains the mapping for the fully qualified class name of the service interface, WSDL service names, and WSDL port names. In addition, the JAX-RPC mapping file provides mappings for WSDL bindings, WSDL port types, WSDL messages, and so forth. And once again, the good news is that you needn't worry about the WSDL file (Code Sample 4) of the JAX-RPC mapping file (Code Sample 5) in order to develop, deploy, and use web services.

Code Sample 5: mapping.xml

<?xml version="1.0" encoding="UTF-8"?>
<java-wsdl-mapping version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd">
<package-mapping>
<package-type>math</package-type>
<namespaceURI>urn:Foo</namespaceURI>
</package-mapping>
<package-mapping>
<package-type>math</package-type>
<namespaceURI>urn:Foo</namespaceURI>
</package-mapping>
<service-interface-mapping>
<service-interface>math.MyFirstService</service-interface>
<wsdl-service-name
xmlns:serviceNS="urn:Foo">serviceNS:MyFirstService</wsdl-service-name>
<port-mapping>
<port-name>MathFacePort</port-name>
<java-port-name>MathFacePort</java-port-name>
</port-mapping>
</service-interface-mapping>
<service-endpoint-interface-mapping>
<service-endpoint-interface>math.MathFace</service-endpoint-interface>
<wsdl-port-type xmlns:portTypeNS="urn:Foo">portTypeNS:MathFace</wsdl-port-type>
<wsdl-binding xmlns:bindingNS="urn:Foo">bindingNS:MathFaceBinding</wsdl-binding>
<service-endpoint-method-mapping>
<java-method-name>add</java-method-name>
<wsdl-operation>add</wsdl-operation>
<method-param-parts-mapping>
<param-position>0</param-position>
<param-type>int</param-type>
<wsdl-message-mapping>
<wsdl-message
xmlns:wsdlMsgNS="urn:Foo">wsdlMsgNS:MathFace_add</wsdl-message>
<wsdl-message-part-name>int_1</wsdl-message-part-name>
<parameter-mode>IN</parameter-mode>
</wsdl-message-mapping>
</method-param-parts-mapping>
<method-param-parts-mapping>
<param-position>1</param-position>
<param-type>int</param-type>
<wsdl-message-mapping>
<wsdl-message
xmlns:wsdlMsgNS="urn:Foo">wsdlMsgNS:MathFace_add</wsdl-message>
<wsdl-message-part-name>int_2</wsdl-message-part-name>
<parameter-mode>IN</parameter-mode>
</wsdl-message-mapping>
</method-param-parts-mapping>
<wsdl-return-value-mapping>
<method-return-value>int</method-return-value>
<wsdl-message
xmlns:wsdlMsgNS="urn:Foo">wsdlMsgNS:MathFace_addResponse</wsdl-message>
<wsdl-message-part-name>result</wsdl-message-part-name>
</wsdl-return-value-mapping>
</service-endpoint-method-mapping>
</service-endpoint-interface-mapping>
</java-wsdl-mapping>

5. Packaging and Deploying the Service

A JAX-RPC web service is really a servlet (or a web component, in J2EE terminology), and hence you can use deploytool to package and generate all the necessary configuration files, and deploy the service. If you haven't yet used the deploytool to package and deploy applications, start the J2EE application server (or default domain) and then follow these instructions to package and deploy the math service. For the rest of the article, I will assume that the service can be accessed using the URL http://localhost:8080/math-service/math.

Creating Web Service Clients

Now, let's create a client that accesses the math service you have just deployed. A client invokes a web service in the same way it invokes a method locally. There are three types of web service clients:

 

  1. Static Stub: A Java class that is statically bound to a service endpoint interface. A stub, or a client proxy object, defines all the methods that the service endpoint interface defines. Therefore, the client can invoke methods of a web service directly via the stub. The advantage of this is that it is simple and easy to code. The disadvantage is that the slightest change of web service definition lead to the stub being useless... and this means the stub must be regenerated. Use the static stub technique if you know that the web service is stable and is not going to change its definition. Static stub is tied to the implementation. In other words, it is implementation-specific.
  2. Dynamic Proxy: Supports a service endpoint interface dynamically at runtime. Here, no stub code generation is required. A proxy is obtained at runtime and requires a service endpoint interface to be instantiated. As for invocation, it is invoked in the same way as a stub. This is useful for testing web services that may change their definitions. The dynamic proxy needs to be re-instantiated but not re-generated as is the case with stub.
  3. Dynamic Invocation Interface (DII): Defines javax.xml.rpc.Call object instance for dynamic invocation. Unlike stub and proxy, it must be configured before it can be used. A client needs to provide: operation name, parameter names, types, modes, and port type. As you can tell, much more coding is involved here. The major benefit is that since Call is not bound to anything, there is no impact of changes on the client side (whenever the web service definition changes). The DII client is outside the scope of this article.

1. Static Stub Client

Let's develop a stand-alone client that calls the add method of MyFirstService. It makes the call through a stub, or a local object that acts as a client proxy to the remote service. It is called a static stub because the stub is generated before runtime by the wscompile tool. Before developing the Java client itself, you need to write a configuration file (in XML) that describes the location of the WSDL file (MyFirstService.wsdl). The configuration file is shown in Code Sample 6. I suggest that you create a new subdirectory under apps call it static-stub (where you save the .xml and .java files) and under that a build subdirectory.

Code Sample 6: config-wsdl.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration
xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<wsdl location="http://localhost:8080/math-service/math?WSDL"
packageName="sstub"/>
</configuration>

As you can see, the URL http://localhost:8080/math-service/math?WSDL identifies the location of the WSDL file for MyFirstService. If you try this URL, you'd see something similar to Figure 3 (assuming you have deployed the web service developed above).

Figure 3: MyFirstService.wsd
Figure 3: MyFirstService.wsdl

Click to Enlarge
 

Once you have written the configuration file, you're ready to generate client stubs, using the following command:

prompt> wscompile -gen:client -d build -classpath build config-wsdl.xml

This commands reads the MyFirstService.wsdl (the location of which is specified in the config-wsdl.xml), then generates files based on the information in the WSDL file and on the command-line flags. The -gen:client instructs wscompile to generate the stubs, as well as other needed runtime files such as serializers and value types. The -d flags tells the tool to write the output to the build subdirectory.

Now, you're ready to develop the client. A sample implementation is shown in Code Sample 7. Note that the stub generated earlier is used, and a service endpoint address is used to locate the service http://localhost:8080/math-service/math. As you can see, a stub object is created using the MathFirstService_Impl object generated by the wscompile tool; the endpoint address that the stub uses to access the service is set; and then the stub is cast to the MathFace service endpoint interface; finally, the add method is invoked.

Code Sample 7: MathClient.java

package sstub;

import javax.xml.rpc.Stub;

public class MathClient {

private String endpointAddress;

public static void main(String argv[]) {
try {
// Invoke createProxy() to create a stub object
Stub stub = createProxy();

// Set the endpoint address the stub uses to access the service
stub._setProperty(javax.xml.rpc.Stub.ENDPOINT_ADDRESS_PROPERTY,
"http://localhost:8080/math-service/math");

// Cast the stub to the service endpoint interface (MathFace)
MathFace math = (MathFace) stub;

// Invoke the add method
System.out.println(math.add(12, 24));
} catch (Exception ex) {
ex.printStackTrace();
}
}

private static Stub createProxy() {
// Create a stub object
// Note that MyFirstService_Impl, generated by wscompile, is implementation-specific
return (Stub) (new MyFirstService_Impl().getMathFacePort());
}
}

You can now compile MathClient.java and write the output to the build directory:

C:sunAPPSER~1appsstatic-stub> javac -classpath build -d build MathClient.java

 


Note: If you don't already use Ant, I'd recommend that you learn how to use it. In this article, however, and for the benefit of those who do not use it, I am not using Ant. The easiest way to get things running is to copy all lib/*.jar and lib/endorsed/*.jar to jdkjrelibext; this way, you don't have to worry about the classpath for the JAX-RPC classes.

Run the client:

C:sunAPPSER~1appsstatic-stub> java -classpath build sstub.MathClient

 
  Today, there have been 2 visitors (24 hits) on this page! www.siva2baba.com & shivababa@gmail.com  
 
=> Do you also want a homepage for free? Then click here! <=
||Struts 1.x 2.x | Spring | Strips | Wicket | Tapestry | Seam | JSF | RIFE | DWR | DOJO | EXT | Jquery | Json | Prototype | Hibernate | iBatis | web 2.0 | http://siva2baba.diinoweb.com/files/ and www.siva2baba.com