Friday, October 31, 2008

XML-RPC vs. SOAP vs. REST thoughts and Spring Beans

Recently I am working on the remote API side of my project, and the protocol that we chose is XML-RPC. Somewhere in two blogs returned by Google search suggested that REST > XML-RPC > SOAP. SOAP can only be considered for its wide enterprise adoption and protocol stack (with security management, transaction control, etc.) and therefore it is complicated. Yes, the person created XML-RPC wasn't an expert in XML but it's neat.

Why not REST then? I used to work on design and technical issues of Mule ESB and I was exposed to REST of its sweetness (the simplicity, the CRUD stuff) before more people started to talk about it (now they talk about Cloud). I learned that SOAP is for SOA (Service Oriented Architecture) and REST is for ROA (Resource Oriented Architecture). They are two different paradigms, and the purpose and design of these layers are therefore different, e.g. you don't carry a service/RPC mindset when you create a REST API.

So, no REST for now as IMO it requires more effort to design a proper API. Never I'll create SOAP due to its complexity.

What about JSON-RPC? I had a short discussion regarding this with @ditesh at #myoss@irc.freenode.net. I love JSON for its interoperability and speed (vs. XML parsing). But the available implementations turned me off pretty quickly, most of them stuck in year 2005~2007. For a publicly available remote API, a well-adopted and "mature" protocol is a much better choice.

What about the Spring beans stuff mentioned in the topic? I found the Apache XML-RPC server can't be integrated with Spring naturally (it has but not enough of bean property methods) and the API is quite ugly, e.g. XmlRpcSystemImpl.addSystemHandler() takes a PropertyHandlerMapping, why not XmlRpcListableHandlerMapping?

I took a similar approach suggested by Tomas Salfischberger in his blog and here they are:
  • An implementation of Spring's AbstractController.
  • An extension of PropertyHandlerMapping, this bean is used by the previous.

public class MyXmlRpcController extends AbstractController {
private XmlRpcServletServer server = new XmlRpcServletServer();
private boolean introspectionEnabled = false;

@Override
protected void initServletContext(ServletContext servletContext) {
super.initServletContext(servletContext);
if (this.introspectionEnabled) {
try {
XmlRpcSystemImpl.addSystemHandler((PropertyHandlerMapping) this.server.getHandlerMapping());
} catch (Exception e) {
}
}
}
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.server.execute(request, response);
return null;
}
@Required
public void setHandlerMapping(XmlRpcHandlerMapping serverHandlerMapping) {
this.server.setHandlerMapping(serverHandlerMapping);
}
public void setIntrospectionEnabled(boolean introspectionEnabled) {
this.introspectionEnabled = introspectionEnabled;
}
}

public class MyXmlRpcHandlerMapping extends PropertyHandlerMapping {
private Map serviceMap;

public void init() throws XmlRpcException {
this.load(Thread.currentThread().getContextClassLoader(), serviceMap);
}
@Required
public void setServicesMapping(Map serviceMap) {
this.serviceMap = serviceMap;
}
}


<bean id="xmlRpcHandlerMapping" class="my.MyXmlRpcHandlerMapping" init-method="init">
<property name="servicesMapping">
<map>
<entry key="membershipService" value="my.service.XmlRpcMembershipService"></entry>
</map>
</property>
</bean>
<bean id="urlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>/xmlrpc=xmlRpcController</value>
</property>
</bean>
<bean id="xmlRpcController" class="my.MyXmlRpcController">
<property name="handlerMapping" ref="xmlRpcHandlerMapping"></property>
<property name="introspectionEnabled" value="true"></property>
</bean>


- yc

No comments: