Spring Web Application With Hessian Services As a Maven Project

This post describes how to set up a Maven project for a Spring web application with Hessian Service. It also shows how to set up the deployment for exposing the Hessian service and how to set up a client to consume the Hessian service. The Spring Framework version is 3.1.1.RELEASE and the Hessian version is 4.0.7.

Maven Set Up For Server

Our Maven project has three modules

  • hello-world-api
  • hello-world-impl
  • hello-word-war
1<modules>
2  <module>hello-world-api</module>
3  <module>hello-world-impl</module>
4  <module>hello-world-war</module>
5</modules>

The module hello-world-api contains the interfaces of the services that Hessian server and Hessian client need for the communication. The module hello-world-impl contains the implementation of the services that are deployed on the server side. The module hello-world-war contains the configuration for the servlet container and the configuration which services should be exported as a  Hessian service.

The Service Interface Definition

The module hello-world-api should become a JAR artifact so the packaging jar for this Maven module:

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4
 5  <modelVersion>4.0.0</modelVersion>
 6  <parent>
 7    <groupId>com.github.skosmalla.spring.hessian</groupId>
 8    <artifactId>hello-world-spring-hessian</artifactId>
 9    <version>1.0.0-SNAPSHOT</version>
10  </parent>
11
12  <artifactId>hello-world-api</artifactId>
13
14  <name>Hello World Api</name>
15
16</project>

The jar contains the interfaces of the services. An example

1package com.github.skosmalla.hello.world.spring.hessian;
2
3public interface HelloWorld {
4
5  public String welcome();
6
7}

The Service Implementation

The module hello-world-impl also becomes a JAR artifact. This jar contains the service implementation for the server. The service implementation could look like following code:

 1package com.github.skosmalla.hello.world.spring.hessian;
 2
 3public class HelloWorldImpl implements HelloWorld {
 4
 5  @Override
 6  public String welcome() {
 7    return "Hello World";
 8  }
 9
10}

Thereby this implementation can be used as a Hessian service, it has to be defined as a Spring bean. Therefore we need a Spring configuration file hello-world-service-config.xml. The location for this file is src/main/resources/META-INF/spring. The bean configuration looks like the following code:

1<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
5
6  <bean id="helloWorldService" class="com.github.skosmalla.hello.world.spring.hessian.HelloWorldImpl"/>
7
8</beans>

In this module we have two dependencies, one to the API module and one to the spring-beans module.

 1<dependencies>
 2  <dependency>
 3    <groupId>org.springframework</groupId>
 4    <artifactId>spring-beans</artifactId>
 5  </dependency>
 6  <dependency>
 7    <groupId>com.github.skosmalla.spring.hessian</groupId>
 8    <artifactId>hello-world-api</artifactId>
 9  </dependency>
10</dependencies>

The WAR Deployment

The module hello-world-war  describes the configuration for the server deployment. The artifact of this module becomes a WAR file. Therefore, the packaging of this Maven module is war.

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4
 5  <modelVersion>4.0.0</modelVersion>
 6  <parent>
 7    <groupId>com.github.skosmalla.spring.hessian</groupId>
 8    <artifactId>hello-world-spring-hessian</artifactId>
 9    <version>1.0.0-SNAPSHOT</version>
10  </parent>
11
12  <artifactId>hello-world-war</artifactId>
13
14  <name>Hello World WAR </name>
15
16  <packaging>war</packaging>
17
18  <build>
19    <defaultGoal>install</defaultGoal>
20  </build>
21</project>

Now, we have to do two things for running our server application on a servlet container:

  1. Add configuration of Spring application context with our implementation to the servlet container.
  2. Add configuration to dispatch request to our Hessian service.

To create an ApplicationContext instance in a web application, we have to configure an ContextLoaderListener in our Web Application Deployment Descriptor (location: src/main/webapp/WEB-INF/web.xml):

1<context-param>
2  <param-name>contextConfigLocation</param-name>
3  <param-value>classpath:META-INF/spring/*.xml</param-value>
4</context-param>
5
6<listener>
7  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
8</listener>

The ContextLoaderListener builds the root application context from all Spring configuration files located in the classpath under META-INF/spring (That pattern matches our hello-world-service-config.xml).  But no request can be processed. Therefore we have to configure a servlet that dispatch the request to the service. Here, the Spring Framework supports us with a DispatcherServlet. To use it we have to add that servlet to our Web Application Deployment Descriptor (location: src/main/webapp/WEB-INF/web.xml):

 1<servlet>
 2  <servlet-name>hessian</servlet-name>
 3  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 4  <load-on-startup>1</load-on-startup>
 5</servlet>
 6
 7<servlet-mapping>
 8  <servlet-name>hessian</servlet-name>
 9  <url-pattern>/hessian/*</url-pattern>
10</servlet-mapping>

That configuration means that servlet is named as hessian and it is responsible for all request to the URL http://<URL to the Tomcat instanz>/<webapp-context>/hessian/* . Now, we have to configure the Hessian service interface that are dispatched by the servlet hessian. For it, we have to add a Spring configuration file in the same location like Web Application Deployment Descriptor (src/main/webapp/WEB-INF). The name of that file have to be hessian-servlet.xml (the pattern is <servlet name>-servlet.xml). Here, we configure the Hessian service interface:

1<bean name="/HelloWorldService" class="org.springframework.remoting.caucho.HessianServiceExporter">
2  <property name="service" ref="helloWorldService" />
3  <property name="serviceInterface" value="com.github.skosmalla.hello.world.spring.hessian.HelloWorld" />
4</bean>

That Spring configuration file defines a new application context. It is child application context of the root application context, loaded by the ContextLoaderListener. A child application context can see every bean of the root application context, but the root application context cannot see beans of its child application context (for more information, have look at the Spring Framework reference). The HessianServiceExporter has a reference to the service implementation, defined in the root application context. The URL of that Hessian service interface is http://<URL to the Tomcat instanz>/<webapp-context>/hessian/HelloWorldService (Pattern is http://<URL to the Tomcat instanz>/<webapp-context>/hessian/<bean name of the HessianServiceExporter>). So that these configurations can run in a servlet container, we have to add the dependencies, that contains HessianServiceExporter, DispatcherServlet and ContextLoaderListener to the pom.xml:

 1<dependency>
 2  <groupId>org.springframework</groupId>
 3  <artifactId>spring-web</artifactId>
 4</dependency>
 5<dependency>
 6  <groupId>org.springframework</groupId>
 7  <artifactId>spring-webmvc</artifactId>
 8</dependency>
 9<dependency>
10  <groupId>com.github.skosmalla.spring.hessian</groupId>
11  <artifactId>hello-world-impl</artifactId>
12</dependency>
13<dependency>
14  <groupId>com.caucho</groupId>
15  <artifactId>hessian</artifactId>
16</dependency>

The Hessian dependency is needed at runtime and the hello-world-impl contains our business logic and the spring configuration file for the root application context. With a mvn clean install Maven builds a WAR file in the project's target folder. This WAR file can be deployed on a Tomcat.

The Hessian Test Client With Spring

Now we write a client to test the Hessian service. Therefore, we create a new Maven module.

 1<?xml version="1.0" encoding="UTF-8"?>
 2<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4
 5  <modelVersion>4.0.0</modelVersion>
 6  <parent>
 7    <groupId>com.github.skosmalla.spring.hessian</groupId>
 8    <artifactId>hello-world-spring-hessian</artifactId>
 9    <version>1.0.0-SNAPSHOT</version>
10  </parent>
11
12  <artifactId>hello-world-client</artifactId>
13
14  <name>Hello World Client</name>
15
16</project>

Spring Framework offers a HessianProxyFactoryBean for calling the remote HelloWorld service. The configuration for this HessianProxyFactoryBean could look like the following code snippet:

 1<?xml version="1.0" encoding="UTF-8"?>
 2<beans xmlns="http://www.springframework.org/schema/beans"
 3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 5
 6<bean id="helloWorldService"
 7  class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
 8  <property name="serviceUrl"
 9    value="http:/localhost:8080/hello-world/hessian/HelloWorldService" />
10  <property name="serviceInterface"
11    value="com.github.skosmalla.hello.world.spring.hessian.HelloWorld" />
12</bean>
13</beans>

In the property serviceInterface we define the interface of the Hessian service, here com.github.skosmalla.hello.world.spring.hessian.HelloWorld. In the property serviceUrl we define the URL to the Hessian Service deployed on the Tomcat. In our sample the Tomcat is on localhost with port number 8080 and the web application is hello-world.

Now, this factory bean creates Hessian service proxy for us:

 1package com.github.skosmalla.hello.world.spring.hessian;
 2
 3import org.springframework.context.ApplicationContext;
 4import org.springframework.context.support.ClassPathXmlApplicationContext;
 5
 6public class HessianClient {
 7
 8  public static void main(String[] args) {
 9    ApplicationContext appContext = new ClassPathXmlApplicationContext("META-INF/spring/hessian-config.xml");
10
11    HelloWorld service = (HelloWorld) appContext.getBean("helloWorldService");
12
13    String welcomeMessage = service.welcome();
14
15    System.out.println(welcomeMessage);
16
17  }
18}

The dependencies for the client are the following one:

 1<dependencies>
 2  <dependency>
 3    <groupId>com.github.skosmalla.spring.hessian</groupId>
 4    <artifactId>hello-world-api</artifactId>
 5  </dependency>
 6  <dependency>
 7    <groupId>org.springframework</groupId>
 8    <artifactId>spring-context</artifactId>
 9  </dependency>
10  <dependency>
11    <groupId>org.springframework</groupId>
12    <artifactId>spring-web</artifactId>
13  </dependency>
14  <dependency>
15    <groupId>com.caucho</groupId>
16    <artifactId>hessian</artifactId>
17    <scope>runtime</scope>
18  </dependency>
19</dependencies>

If we start this client we will get "Hello World" on our command line. Now, we have seen a full example how to set up a Hessian service in a Spring web application and how to call such a service remotely. The full code you can find on Github.