Does Resin 4 Support Remoting?
From Resin 4.0 Wiki
Line 168: | Line 168: | ||
that for the URI path. For each bean that has a @Stateless annotation, it registers a HessianServlet programmatically. | that for the URI path. For each bean that has a @Stateless annotation, it registers a HessianServlet programmatically. | ||
− | In about 20 lines of code, you can expose all @Stateless/@Remote beans | + | In about 20 lines of code, you can expose all @Stateless/@Remote beans as remote services using the Hessian protocol using CDI and Servlet 3.0. |
+ | |||
+ | It should be noted that you could define your own annotations to use instead of using @Stateless and @Remote. Also if they were CDI qualifiers than looking up the remote services would be a lot easier as well. |
Revision as of 00:00, 16 May 2012
A frequent question is: Does Resin 4 support EJB remoting?
The short answer is no. The longer answer is that Resin supports Hessian for remoting. Hessian (now Hessian 2) predates many other forms of remoting and is a wicked fast, binary protocol (faster than CORBA, RMI, SOAP, XML-RPC, etc). You could think of Hessian as a high performance binary JSON. Hessian has been ported to many languages. Hessian is a remoting framework and a flexible Java serialization framework.
You can expose any bean as a Hessian remote bean quite easily. Hessian has been around for 10 years, and is very solid. (Both Hessian and Resin are development and maintained by Caucho).
Resin 4 documentation does not have Hessian documentation yet, but Hessian usage has not changed in years. You can find a good tutorial on getting started with Hessian from the Resin 3 documentation. I've tried these tutorial steps in Resin 4 and the tutorial works as advertised.
Resin 4 is Java EE Web Profile certified as such it does not support CORBA, EJB remoting, etc. However Resin does support Java Dependency Injection (CDI), which allows you to easily find beans with certain annotations. What follows is a simple example that finds all @Stateless beans that have @Remote interfaces and automatically exposes those beans as remote hessian objects:
First let's show our remote interface
Contents |
Remote interface
package example; import javax.ejb.Remote; @Remote public interface HelloWorld { String hello(); }
Hello Service
package example; import javax.ejb.Stateless; import javax.inject.Named; @Stateless @Named public class HelloService implements HelloWorld{ @Override public String hello() { return "Hello world!"; } }
HelloService client
package example; import com.caucho.hessian.client.HessianProxyFactory; public class HelloClient { public static void main(String[] args) throws Exception { String url = "http://localhost:8080/hessian/helloService"; HessianProxyFactory factory = new HessianProxyFactory(); HelloWorld hello = (HelloWorld) factory.create(HelloWorld.class, url); System.out.println("Hello: " + hello.hello()); } }
You could just register this bean via a web.xml file as follows:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class> <init-param> <javaee:param-name>home-class</javaee:param-name> <javaee:param-value>example.HelloService</javaee:param-value> </init-param> <init-param> <javaee:param-name>home-api</javaee:param-name> <javaee:param-value>example.HelloWorld</javaee:param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/helloService</url-pattern> </servlet-mapping> </web-app>
But what if you wanted to include 20 or 30 services in the war file. Using XML to configure all of those would be a drag. Death by XML!
Well, Servlet 3.0 allows you to programmatically add Servlets, and CDI allows you to discover Java EE managed beans. So instead of configuring XML, we can look up the beans and then configure hessian servlets for out beans as follows:
RemoterListener is a Application Lifecycle Listener class that uses CDI to lookup @Stateless @Remote beans
package example; import java.util.Set; import javax.ejb.Stateless; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletRegistration; import javax.servlet.annotation.WebListener; import javax.ejb.Remote; import javax.inject.Inject; @WebListener public class RemoterListener implements ServletContextListener { @Inject BeanManager beanManager; public void contextInitialized(ServletContextEvent event) { ServletRegistration.Dynamic registration; Set<Bean<?>> beans = beanManager.getBeans(Object.class); for (Bean<?> bean : beans) { System.out.println(bean.getBeanClass()); System.out.println(bean.getName()); if (!bean.getBeanClass().isAnnotationPresent(Stateless.class)) { continue; } if (bean.getName() == null || bean.getName().isEmpty()) { continue; } registration = event.getServletContext().addServlet( "hessian-" + bean.getName(), "com.caucho.hessian.server.HessianServlet"); registration.setInitParameter("home-class", bean.getBeanClass() .getName()); Class<?>[] interfaces = bean.getBeanClass().getInterfaces(); for (Class<?> interface_ : interfaces) { if (interface_.isAnnotationPresent(Remote.class)) { registration.setInitParameter("home-api", bean.getBeanClass() .getName()); break; } } registration.addMapping("/" + bean.getName()); } } /** * @see ServletContextListener#contextDestroyed(ServletContextEvent) */ public void contextDestroyed(ServletContextEvent event) { } }
RemoterListener is a Application Lifecycle Listener class that uses CDI to lookup @Stateless @Remote beans. It takes the name of the bean, and and uses that for the URI path. For each bean that has a @Stateless annotation, it registers a HessianServlet programmatically.
In about 20 lines of code, you can expose all @Stateless/@Remote beans as remote services using the Hessian protocol using CDI and Servlet 3.0.
It should be noted that you could define your own annotations to use instead of using @Stateless and @Remote. Also if they were CDI qualifiers than looking up the remote services would be a lot easier as well.