Archive for February, 2005

Spring’s Quest for SOAP draws at an end

This is the third post in a series about using Spring and SOAP. It started with this post, then I rambled on, and this is probably the conclusion.

When I started this quest, it seemed simple. I wanted to expose my business interfaces via SOAP. I wanted the WSDLs to be generated automatically, and I wanted the value objects I used as parameters to be converted automatically. Most of all, I didn’t want to change my business interface just to support a remoting protocol. After all, I might want to support another protocol in a year or so, and did not want to change it again then.

While the quest seemed easy, I had to fight through fightthroughmanyspecifications just to figure out how SOAP was supposed to work in Java.

Then, the cavalry arrived, in the form of Dan Diephouse. He pointed me to his excellent XFire framework, which he updated this weekend to include Spring support. With the code currently in the XFire CVS (which will be part of the M4 release), you can export you business interface ServiceManager, with the implementing bean called myService like so:


  
  
    jteam.managers.ServiceManager
  
    
    

Just what I wanted! :-) The above is just a short extract; for more information on XFire and Spring, visit this web page.

Of the three Java SOAP frameworks I’ve tried (the other two being Axis and ActiveSOAP, I tend to prefer XFire. Axis seems too complicated, and ActiveSOAP just doesn’t feel finished. XFire is simple, and does what it needs to do.

Comments off

Spring XmlRpcServiceExporter

Gary Blomquist asked me to share the Spring ServiceExporter mentioned in the previous post. Here is is:

package jteam.remoting.xmlrpc;
 
import java.io.OutputStream;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.apache.xmlrpc.XmlRpcServer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.remoting.support.RemoteExporter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.support.WebContentGenerator;
 
/**
 * Web controller that exports the specified service bean as XML-RPC service
 * endpoint, accessible via a XML-RPC proxy.
 *
 * XML-RPC is a simple, SOAP-like protocol. For more information, see the
 * XML-RPC website.
 *
 * @author Arjen Poutsma
 */
public class XmlRpcServiceExporter
  extends RemoteExporter 
  implements Controller, InitializingBean {
    private XmlRpcServer server;
 
    public void afterPropertiesSet()
  throws Exception {
        server = new XmlRpcServer();
        server.addHandler(getServiceInterface().getName(), getProxyForService());
    }
 
    /**
     * Process the incoming XML-RPC request and create a XML-RPC response.
     *
     * @param request current HTTP request
     * @param response current HTTP response
     * @return null
     * @throws Exception in case of errors.
     */
    public ModelAndView handleRequest(HttpServletRequest request, 
                                      HttpServletResponse response)
    throws Exception {
        if (!WebContentGenerator.METHOD_POST.equals(request.getMethod())) {
            throw new ServletException(“XmlRpcServiceExporter only supports ” +
              “POST requests”);
        }
        byte[] result = server.execute(request.getInputStream());
        response.setContentType(“text/xml”);
        response.setContentLength(result.length);
        OutputStream output = response.getOutputStream();
        output.write(result);
        output.flush();
 
        return null;
    }
 
}

Nothing fancy. The full name of the service interface is used as a handler name. So if your interface is called jteam.businesslogic.TestManager, it gets exposed as jteam.businesslogic.TestManager.

This class depends on the Apache XML-RPC library to do the actual XML-RPC handling. This library does have it’s weaknesses: it uses the old, synchronized collections (Vector and Hashtable), and it does not handle XML-RPC structs very well, since it converts a struct into a Hashtable with the string names mapped to the value.

I would have preferred a more XStream-like approach, where the following struct:

<struct>
   <member>
      <name>lowerBound</name>
      <value><i4>18</i4></value>
   </member>
   <member>
      <name>upperBound</name>
      <value><i4>139</i4></value>
   </member>
</struct>

would have been converted into a bean with lowerBound and upperBound properties. If it bothers me too much, I will add this functionality myself.

Comments (3)

SOAP is hard! I love shopping!

In my previous post, I talked about exporting Spring business interfaces via SOAP to integrate with a .NET client. I said:

How hard can it be, right?

Well, as it turned out, it is pretty hard. While the basic idea of sending XML messages across HTTP is simple, the SOAP spec is not. It really suffers from specification creep.

Instead of making matters easier (like Microsoft has done with its implementation of the SOAP standard), Sun has decided to make matters even harder. I found four (!) specifications which relate to SOAP and Java. These are:

  1. JAX-RPC, which focusses on the J2EE side of things,
  2. JAXM, which is somewhat more lightweight,
  3. SAAJ, which provides the standard API to handle SOAP messages, and finally
  4. JWSDL, which provides the standard API to generate WSDLs.

Don’t ask me how these standards relate to one another. I honestly don’t know.

Most of these specs only define interfaces, so you also have to find someone crazy enough to implement them. (Which reminds me: I would love to be a spec writer at Sun. Just designing interfaces all day, and let the mere mortals implement them). No wonder Axis is so complicated, it is because of the SOAP and JAX-RPC specs!

In the end, I got so fed up with SOAP, that I decided to look into a totally different way of exposing Web Services: XML-RPC. What a great spec! It fits on one sheet of paper!

Withing 15 minutes, I had a working XmlRpcServiceExporter, which exported the business interface of my Spring-managed bean to a .NET client. On the Java server-side, I used Apaches XML-RPC implementation; on the .NET client-side, I used Charles Cook’s excellent XML-RPC.NET.

The Apache XML-RPC library does seem to have one problem, though: it implements struct values as Hashtable objects, and not as JavaBeans. XML-RPC.NET does convert the properties and fields of a class to values in a structs, like one expects.

Comments (3)

Spring and SOAP

Since JTeam is such a hip Java shop, and since one of the founders is co-writing the book on the subject, we try to use the Spring framework whenever we can.

For an in-house project, I wanted to expose a Spring-managed business interface by SOAP to a Windows Forms .NET client. Unfortunately, there is no SOAP support in Spring yet, so I decided to write it myself. How hard can it be, right? :-)

Instead of delving into code, I started with the exterior: the way I wanted the SOAP support to be defined in my beans definitions. I wanted it to be similar to the standard remoting export services found in subpackages of org.springframework.remoting (like the HessianServiceExporter). Thus, I wanted it to look like this:


  
  
    jteam.managers.ServiceManager
  

Happily, I started to code the SoapServiceExporter. I did not have the urge to write my own SOAP server, so I needed a Java-based SOAP implementation to which I could relay the messages. I started with Axis, since that seems to be standard in Java land. All seemed well when I read the Architecture Guide: it seemed pretty pluggable. However, when I inspected the source of AxisServlet, I saw that the doPost method - which is most important - was about two hundred lines of message-handling logic. No way that I was going to copy-paste that into my SoapServiceExporter to achieve the same results.

Next up was ActiveSOAP, which has a much lighter feel to it. It seems to be pretty usable for my demands, except for the fact that it only seems to export interface methods which have one parameter, which you can see here and here. I wonder why that is.

So that’s where I am right now. In some future post, I will conclude this tale…

Update: Since I originally wrote this post, my thoughts on Web Services have changed considerably. Read this series of articles to see how.

Comments (7)