Caucho Technology
documentation
examples
changes

overview
quick start
installation
command-line
configuration
admin
amber
clustering
caching
database
deployment
ejb 3.0
embedding
filters
hessian
hmtp
ioc
jsp
logging
messaging
performance
quercus/php
remoting
scheduled tasks
security
server push
servlets
third-party
troubleshooting
virtual hosting
watchdog
webapp
xml and xslt

resin remoting


Resin's remoting lets applications write services as plain Java objects and export them with a choice of protocols, including Hessian, Burlap, CXF (SOAP), XFire. Because Resin activates the service as an IoC singleton, the service can use any of Resin's IoC capabilities, including dependency injection, AOP interception, EJB transactions, and event handling.

For applications which need to use a custom protocol, making a new driver for a protocol is also straightforward.

Example: Hello, World

The Hello, World example shows the primary steps involved in creating a Resin remoting service:

  1. Creating the public API
  2. Creating the Java implementation
  3. Configuring the service in the resin-web.xml and choosing the protocol
  4. Configuring and using the client

API - defining the protocol

Defining the protocol cleanly and clearly is the most critical aspect of designing a remote service. Because you will be sharing the protocol API among many other developers using different languages, it's critical to create a good design.

The API classes are used for both the client and the server, ensuring compatibility. Even when the clients are expected to be written in a different language, e.g. Flash, C# or JavaScript, the API serves both as documentation and validation of the protocol. In the case of C#, the API can be translated automatically using reflection for strict compile-time validation.

In this example, the API is easy. It's just a single method call hello returning a greeting string.

Example: Hello.java - API
package qa;

public interface Hello {
  public String hello();
}

Service - implementing the service

The service implementation is a plain Java object that can optionally use Resin-IoC capabilities for dependency injection. The service is multithreaded, so it's the service-developer's responsibility to handle any synchronization or transaction issues, just like writing a servlet.

In this example, the implementation is trivial, just returning the "hello, world" string. More complicated services might delegate to WebBeans or EJB services.

Example: MyService.java - Service
package qa;

public class MyService implements Hello {
  public String hello()
  {
    return "hello, world";
  }
}

Configuration - exporting the protocol

Web-based remoting protocols are exported using the HTTP protocol with well-known URLs; they're essentially fancy servlets. Resin lets you configure your services just like a servlet. The only additional configuration necessary is choosing the protocol.

Protocol drivers like Hessian or CXF register the protocol implementation with a URI scheme like "hessian:" or "cxf:". Your service configuration will just select the appropriate protocol in a <protocol> configuration tag.

In the example, we'll use Hessian, since it's a fast binary protocol with several language implementations. If you want to export multiple protocol bindings, you can just add new <servlet-mapping> definitions.

Example: WEB-INF/resin-web.xml - Hessian Service
<web-app xmlns="http://caucho.com/ns/resin">

  <servlet-mapping url-pattern="/hello" servlet-class="qa.MyService">
    <protocol uri="hessian:"/>
  </servlet-mapping>

</web-app>

We can easily change the protocol to use CXF instead of Hessian by changing the scheme from "hessian:" to "cxf:".

Example: WEB-INF/resin-web.xml - CXF Service
<web-app xmlns="http://caucho.com/ns/resin">

  <servlet-mapping url-pattern="/hello" servlet-class="qa.MyService">
    <protocol uri="cxf:"/>
  </servlet-mapping>

</web-app>

Client servlet - using the protocol

On the client side, the application needs a proxy to invoke the server methods. Since the protocols themselves are generic, the client will work with any server even if written in a different language like C#, as long as the protocol is compatible.

The client uses Resin's dependency injection to get a client proxy for the protocol. By using dependency injection, the client code remains independent of the protocol choice or any protocol-setup housekeeping. The only dependency is on the client API itself. Because the client uses the type-safe API, the Java compiler validates the protocol, making compatibility as certain as possible.

The @javax.webbeans.In annotation asks Resin to lookup the qa.Hello client stub that's been configured and gives it to the servlet. Since the client stub is thread-safe it can be safely used in the servlet code.

Example: qa/MyServlet.java - Servlet Client
package qa;

import java.io.*;
import javax.servlet.*;
import javax.webbeans.*;

public class MyServlet extends GenericServlet {
  @In private Hello _hello;

  public void service(ServletRequest request,
                      ServletResponse response)
    throws IOException
  {
    out.println("hello: " + _hello.hello());
  }
}

Although most clients will just have a single Hello proxy and can use the @In tag, more complicated applications can use the @Named tag or even custom @BindingTag annotations to select the right proxy. The Resin IoC documentation has more details.

Configuration - selecting the protocol

To configure the client, you need to specify the protocol type, the URL, and the API class in a <remote-client> tag in the resin-web.xml. Since the client code uses injection to get the proxy, we can switch protocols if necessary.

The example uses Hessian, so the uri attribute uses a "hessian:" scheme with Hessian's url parameter. The API class is qa.Hello.

Example: WEB-INF/resin-web.xml - Hessian Client
<web-app xmlns="http://caucho.com/ns/resin">

  <remote-client class="qa.Hello"
                 uri="hessian:url=http://localhost:8080/hello"/>

  <servlet-mapping url-pattern="/demo"
                   servlet-class="qa.MyServlet"/>

</web-app>

Since the client code only depends on the proxy API, changing to use CXF (SOAP) just requires changing the protocol scheme from "hessian:" to "cxf:".

Example: WEB-INF/resin-web.xml - CXF Client
<web-app xmlns="http://caucho.com/ns/resin">

  <remote-client class="qa.Hello"
                 uri="cxf:url=http://localhost:8080/hello"/>

  <servlet-mapping url-pattern="/demo"
                   servlet-class="qa.MyServlet"/>

</web-app>

Available Protocols

Resin 3.1.5 has the following protocol drivers available:

  • hessian: The Hessian protocol is a fast, compact binary protocol with implementations available in a large number of languages including Flash, PHP and C#.
  • burlap: The Burlap protocol is the XML-based cousin of Hessian.
  • cxf: The CXF driver uses the Apache CXF project for SOAP client and server protocols.

Protocol Plugin Architecture

You can extend Resin's remoting protocols by adding a plugin for either the server or client. In either case, the required API is deliberately kept simple.

Server plugins

com.caucho.remote.server.ProtocolServletFactory
public interface ProtocolServletFactory {

  public Servlet createServlet(Class serviceClass, Object service)
    throws ServiceException;

}
Example: HessianProtocolServletFactory
package com.caucho.remote.hessian;

import com.caucho.hessian.server.*;
import com.caucho.remote.*;
import com.caucho.remote.server.*;

import javax.servlet.*;

public class HessianProtocolServletFactory
  extends AbstractProtocolServletFactory
{
  public Servlet createServlet(Class serviceClass, Object service)
    throws ServiceException
  {
    HessianServlet servlet = new HessianServlet();

    servlet.setHome(service);
    servlet.setHomeAPI(getRemoteAPI(serviceClass));
    
    return servlet;
  }
}

Resin's URI aliases are configured by property files in WEB-INF/services/com.caucho.config.uri. Each interface has its property file specifying the implementation class for each URI scheme. In this case, the interface is com.caucho.remote.server.ProtocolServletFactory, so it the scheme mappings are added to a file with the same name:

com.caucho.remote.server.ProtocolServletFactory
burlap=com.caucho.remote.burlap.BurlapProtocolServletFactory
hessian=com.caucho.remote.hessian.HessianProtocolServletFactory

Client plugins

com.caucho.remote.client.ProtocolProxyFactory
public interface ProtocolProxyFactory
{
  public Object createProxy(Class api);
}
Example: HessianProtocolProxyFactory.java
package com.caucho.remote.hessian;

import com.caucho.hessian.client.*;
import com.caucho.remote.*;
import com.caucho.remote.client.*;

public class HessianProtocolProxyFactory
  extends AbstractProtocolProxyFactory
{
  private HessianProxyFactory _factory = new HessianProxyFactory();

  private String _url;

  public void setURL(String url)
  {
    _url = url;
  }
  
  public Object createProxy(Class api)
  {
    try {
      return _factory.create(api, _url);
    } catch (Exception e) {
      throw ServiceException(e);
    }
  }
}

Copyright © 1998-2008 Caucho Technology, Inc. All rights reserved.
Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.