Spring Hessian Integration
When implementing Hessian in a Spring application, the original Hessian API does not apply. Luckily, the Spring team realized the value of Hessian a long time ago and provided solid integration for creating Hessian components as simple Java objectswithout the need to extend specialized servlets.
To demonstrate Spring's Hessian integration, this section walks you through setting up some common interfaces. First, use the following two classes to create a service that will allow saving/updating/deleting a simple Person POJO:
public class Person implements Serializable {
private Integer id;
private String firstName;
private String lastName;
private Calendar birthDate;
public Person() {
super();
}
public Person(String firstName, String lastName, Calendar birthDate) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.birthDate = birthDate;
...getters and setters...
}
}
Person DAO service:
public interface IPersonService {
Person get(Integer id);
Person add(Person person);
void delete(Integer personId);
void update(Person person);
}
Both these classes are part of a common library shared on both endpoints.
Setting Up the Server Endpoint
In the Spring server-side application, create a regular Java component that implements your service interface. Here's an example of how to do that:
@Service("personService")
public class PersonService implements IPersonService {
//map used for simulating data storage
private static Map<Integer,Person> people = new ConcurrentHashMap<Integer, Person>();
private static AtomicInteger keyGenerator = new AtomicInteger(0);
@Override
public Person add(Person person) {
if (person.getId() == null) {
Integer id = keyGenerator.addAndGet(1);
person.setId(id);
people.put(id,person);
return person;
} else {
throw new RuntimeException("Person already exists!");
}
}
@Override
public void update(Person person) {
if (person.getId() != null) {
people.put(person.getId(), person);
} else {
throw new RuntimeException("Person must be saved first!");
}
}
@Override
public void delete(Integer personId) {
people.remove(personId);
}
@Override
public Person get(Integer id) {
return people.get(id);
}
}
As you can see, this component does
not need to extend the previously mentioned Hessian servlet. Also, the
@Service Spring stereotype annotation eliminates the need to explicitly define the bean in an XML configuration. However, exposing the component via Spring does involve a series of steps.
First, in web.xml, add the Spring remoting servlet and map it to a URI:
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/remoting/*</url-pattern>
</servlet-mapping>
The Spring remoting servlet will expect a new Spring application context file, which is usually called
remoting-servlet.xml (separate from the usual
beans.xml used by the rest of the application). In the context file, you have to expose your service via a HessianServiceExporter class:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.devx.hessian.server"/>
<bean name="/PersonService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="personService" />
<property name="serviceInterface" value="com.dexv.hessian.IPersonService"/>
</bean>
</beans>
The
context elements activate Spring's new annotation-based context support (to avoid unnecessary XML configuration) and tell it which package to use as the base for searching for components. The PersonService implementation is then injected into the HessianServiceExporter class instance.
If you run the server app (from the code sample attached to this article) and access the /remoting/PersonService URI via a regular browser, you will get a notice that Hessian is listening, although unable to process a typical browser request:
HTTP ERROR: 405
HessianServiceExporter only supports POST requests
RequestURI=/remoting/PersonService