Monday, November 19, 2007

Monitor SOAP messages

While developing Web Services at times one has to look for what is going out and coming in during web service interaction. Eclipse has a built-in TCP/IP Monitor but somehow I did not have a good experience using it.

Apache SOAP project has small utility called TCP Tunnel/Monitor, which is available here. TCP Tunnel/Monitor can be started using follwing command-

set CLASSPATH=%CLASSPATH%;./soap.jar;
java org.apache.soap.util.net.TcpTunnelGui 80 localhost 8080

Here first option 80 is the port where TcpTunnel will listen on your machine (localhost). The second parameter is the target address (the local machine in this case). The final parameter 8080 is the port where it will forward the calls to desired server as specified in 2nd parameter.

The TCP Tunnel/Monitor application is really just a simple proxy application that includes a visual interface to view the request response XML. TCP Tunnel/Monitor will display a window with two text areas:




* The text area on the left shows the request.
* The text area on the right shows the response received from the target server.

Tuesday, September 04, 2007

Struts 2 does not like mathematical operators in attribute names

If mathematical operators (+, -, *, /) are made part of an attribute name then Struts 2 may mis-interpret them during lookups. Say if one uses "user-name" as attribute name for storing an object in request scope. On attempt of retrieving this variable from request scope using-

request.getAttribute("user-name");

if Struts 2 does not find this variable in request scope then it looks in ValueStack using OGNL. The OGNL interprets "user-name" as an expression something like ${user - name} and looks for two attributes "user" & "name" and returns difference of value of "user" and "name". This will lead to ClassCastException in your code when you do something like-

User user = (User) request.getAttribute("user-name");

because Struts 2 will return a BigInteger.

Moral of the story, never use mathematical operators in attribute names at least with Struts 2 and of course with JSTL also.

Tuesday, August 14, 2007

Bottom Up JAX-RPC web service with JWSDP

A simple step by step guide to develop a bottom up web service using Java Web Services Developer Pack.

Step #1 Install JWSDP

Download Java Web Services Developer Pack 1.6 (JWSDP) from http://java.sun.com/webservices/downloads/webservicespack.html and install it. The installation directory will be called hereafter as $JWSDP_HOME.

Step #2 Write code and Package war file

Write an interface and implementation of it. This interface will be exposed as web service through servlet end-point. Write a configuration file named jaxrpc-ri.xml and save it in WEB-INF folder of the project. This configuration file contains information about web service interface and it’s implementation, location of WSDL file, web service URL. All these information will be used by JWSDP at the time of processing input war file for generating web service.

The jaxrpc-ri.xml looks like below-

<?xml version="1.0" encoding="UTF-8"?>
  <webServices
    xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/dd"
    version="1.0"
    targetNamespaceBase="http://myhost/myService"
    typeNamespaceBase="http://myhost/types"
    urlPatternBase="/myWs">

  <endpoint
    name="MyWebService"
    displayName="My Web Service"
    description="Test JAX-RPC web service"
    wsdl="/WEB-INF/myWs.wsdl"
    interface="myPackage.MyWsInterface"
    implementation="myPackage.MyWsImplementation" />

  <endpointMapping
    endpointName="MyWebService"
    urlPatternBase="/myWs" />

</webServices>
The web.xml must have following entries-
<listener>
  <listener-class>com.sun.xml.rpc.server.http.JAXRPCContextListener</listener-class>
</listener>
<servlet>
  <servlet-name>myWs</servlet-name>
  <servlet-class>com.sun.xml.rpc.server.http.JAXRPCServlet</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>myWs</servlet-name>
  <url-pattern>/myWs</url-pattern>
</servlet-mapping>

Step #3 Process war file

Copy above created war file say myWS-in.war to $JWSDP_HOME/jaxrpc/bin directory and create a directory named tmp there. Open command prompt and go to above mentioned directory and fire following command-

$ wsdeploy -o myWs.war myWs-in.war -keep -tmpdir ./tmp -verbose

This will create a war file
myWs.war, which is ready to be deployed on Tomcat.

Step #4 Deploy Processed war file on Tomcat

Now deploy the processed war file,
myWs.war on Tomcat and start Tomcat.

Step #5 Generate Web Service client

Create a file named config.xml with following contents-
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <wsdl location="http://localhost:8080/myWs/myWs?WSDL"
  packagename="myWsClient" />
</configuration>
Here location is the URL of the web service WSDL, which may change according to server installation, hence update it accordingly and packageName is the package name of the generated web service client classes, which could also be changed to anything.
Save config.xml in $JWSDP_HOME/jaxrpc/bin directory. Now fire following command-
$ wscompile -gen:client -keep config.xml

This will create a directory name
$JWSDP_HOME/jaxrpc/bin/myWsClient, create a jar file containing this directory. This way web service client is ready. This directory name depends upon the packageName specified in config.xml.

An example of client accessing web service is given below-
public class WsTest {

  public static void main(String[] args) {
    try {
      MyWsImpl stub = new MyWsImplService_Impl().getXXX();
      ((Stub)stub)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, "http://myHost/myWs/myWs");
      // call the desired method
      stub.xxxXXX(. . .);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}