Enterprise Java

Spring Remoting Support and Developing RMI Service

The development of remote-enabled services is eased by Spring remoting support. Currently, Spring supports the following remoting technologies: Remote Method Invocation (RMI), HTTP Invoker, Hessian, Burlap, JAX-RPC, JAX-WS and JMS.

Remote Method Invocation (RMI) : Spring supports RMI via RmiProxyFactoryBean and RmiServiceExporter. RmiServiceExporter exports any Spring-managed bean as an RMI service and registers. RmiProxyFactoryBean is a factory bean creating a proxy for an RMI service. This proxy object talks with remote RMI services on behalf of the client.

Spring’s HTTP invoker : Spring HTTP invokers use the standard Java serialization mechanism to expose services through HTTP. Spring supports HTTP invoker infrastructure via HttpInvokerProxyFactoryBean and HttpInvokerServiceExporter. HttpInvokerServiceExporter that exports the specified service bean as HTTP invoker service endpoint, accessible via an HTTP invoker proxy. HttpInvokerProxyFactoryBean is a factory bean for HTTP invoker proxies.

Hessian : Hessian offers a binary HTTP-based remoting protocol. Spring supports Hessian via HessianProxyFactoryBean and the HessianServiceExporter.

Burlap : Burlap is Caucho’s XML-based alternative to Hessian. Spring provides support classes such as BurlapProxyFactoryBean and BurlapServiceExporter.

JAX-RPC : Spring provides remoting support for web services via JAX-RPC (J2EE 1.4?s web service API).

JAX-WS : Spring provides remoting support for web services via JAX-WS (the successor of JAX-RPC, as introduced in Java EE 5 and Java 6).

JMS : The JMS remoting support in the Spring is provided by the JmsInvokerServiceExporter and JmsInvokerProxyFactoryBean classes.

Let us look at Spring RMI support to develop Spring RMI Service & Client.

Used Technologies :

JDK 1.6.0_31
Spring 3.1.1
Maven 3.0.2

STEP 1 : CREATE MAVEN PROJECT

A maven project is created as below. (It can be created by using Maven or IDE Plug-in).

STEP 2 : LIBRARIES

Spring dependencies are added to Maven’ s pom.xml.

<!-- Spring 3.1.x dependencies -->
<properties>
    <spring.version>3.1.1.RELEASE</spring.version>
</properties>
 
<dependencies>
            <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
<dependencies>

STEP 3 : CREATE USER CLASS

A new User Class is created.

package com.otv.user;
 
import java.io.Serializable;
 
/**
 * User Bean
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class User implements Serializable {
 
    private long id;
    private String name;
    private String surname;
 
    /**
     * Get User Id
     *
     * @return long id
     */
    public long getId() {
        return id;
    }
 
    /**
     * Set User Id
     *
     * @param long id
     */
    public void setId(long id) {
        this.id = id;
    }
 
    /**
     * Get User Name
     *
     * @return long id
     */
    public String getName() {
        return name;
    }
 
    /**
     * Set User Name
     *
     * @param String name
     */
    public void setName(String name) {
        this.name = name;
    }
 
    /**
     * Get User Surname
     *
     * @return long id
     */
    public String getSurname() {
        return surname;
    }
 
    /**
     * Set User Surname
     *
     * @param String surname
     */
    public void setSurname(String surname) {
        this.surname = surname;
    }
 
    @Override
    public String toString() {
        StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("Id : ").append(getId());
        strBuilder.append(", Name : ").append(getName());
        strBuilder.append(", Surname : ").append(getSurname());
        return strBuilder.toString();
    }
}

STEP 4 : CREATE ICacheService INTERFACE

ICacheService Interface representing a remote cache service interface is created.

package com.otv.cache.service;
 
import java.util.concurrent.ConcurrentHashMap;
 
import com.otv.user.User;
 
/**
 * Cache Service Interface
 *
 * @author  onlinetechvision.com
 * @since   27 Feb 2012
 * @version 1.0.0
 *
 */
public interface ICacheService {
 
    /**
     * Get User Map
     *
     * @return ConcurrentHashMap User Map
     */
    public ConcurrentHashMap<long, user> getUserMap();
 
}

STEP 5 : CREATE CacheService CLASS

CacheService Class is created by implementing ISchedulerService Interface. It provides access to the remote cache…

package com.otv.cache.service;
 
import java.util.concurrent.ConcurrentHashMap;
 
import com.otv.user.User;
 
/**
 * Cache Service Implementation
 *
 * @author  onlinetechvision.com
 * @since   6:04:49 PM
 * @version 1.0.0
 *
 */
public class CacheService implements ICacheService {
 
    //User Map is injected...
    ConcurrentHashMap<long, user> userMap;
 
    /**
     * Get User Map
     *
     * @return ConcurrentHashMap User Map
     */
    public ConcurrentHashMap<long, user> getUserMap() {
        return userMap;
    }
 
    /**
     * Set User Map
     *
     * @param ConcurrentHashMap User Map
     */
    public void setUserMap(ConcurrentHashMap<long, user> userMap) {
        this.userMap = userMap;
    }
 
}

STEP 6 : CREATE IRMIUserService INTERFACE

IRMIUserService Interface representing RMI service interface is created. Also, it provides remote methods for the RMI Clients…

package com.otv.rmi.server;
 
import java.util.List;
 
import com.otv.user.User;
 
/**
 * RMI User Service Interface
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public interface IRMIUserService {
 
    /**
     * Add User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean addUser(User user);
 
    /**
     * Delete User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean deleteUser(User user);
 
    /**
     * Get User List
     *
     * @return List user list
     */
    public List<User> getUserList();
 
}

STEP 7 : CREATE RMIUserService CLASS

RMIUserService Class(a.k.a RMI Object) is created by implementing IRMIUserService Interface.

package com.otv.rmi.server;
 
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
 
import com.otv.cache.service.ICacheService;
import com.otv.user.User;
 
/**
 * RMI User Service Implementation
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIUserService implements IRMIUserService {
 
    private static Logger logger = Logger.getLogger(RMIUserService.class);
 
    //Remote Cache Service is injected...
    ICacheService cacheService;
 
    /**
     * Add User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean addUser(User user) {
        getCacheService().getUserMap().put(user.getId(), user);
        logger.debug("User has been added to cache. User : "+getCacheService().getUserMap().get(user.getId()));
        return true;
    }
 
    /**
     * Delete User
     *
     * @param  User user
     * @return boolean response of the method
     */
    public boolean deleteUser(User user) {
        getCacheService().getUserMap().put(user.getId(), user);
        logger.debug("User has been deleted from cache. User : "+user);
        return true;
    }
 
    /**
     * Get User List
     *
     * @return List user list
     */
    public List<User> getUserList() {
        List<User> list = new ArrayList<User>();
        list.addAll(getCacheService().getUserMap().values());
        logger.debug("User List : "+list);
        return list;
    }
 
    /**
     * Get RMI User Service
     *
     * @return IRMIUserService RMI User Service
     */
    public ICacheService getCacheService() {
        return cacheService;
    }
 
    /**
     * Set RMI User Service
     *
     * @param IRMIUserService RMI User Service
     */
    public void setCacheService(ICacheService cacheService) {
        this.cacheService = cacheService;
    }
}

STEP 8 : CREATE RMIServerStarter CLASS

RMI Server Starter Class is created. It starts the RMI Server.

package com.otv.rmi.server.starter;
 
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
/**
 * RMI Server Starter
 *
 * @author  onlinetechvision.com
 * @since   27 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIServerStarter {
 
    public static void main(String[] args) {
 
        //RMI Server Application Context is started...
        new ClassPathXmlApplicationContext("rmiServerAppContext.xml");
    }
}

STEP 9 : CREATE rmiServerAppContext.xml

RMI Server Application Context’ s content is shown as below.

<beans xmlns="http://www.springframework.org/schema/beans"
    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">
 
    <!-- Beans Declaration -->
    <bean id="UserMap" class="java.util.concurrent.ConcurrentHashMap" />
 
    <bean id="CacheService" class="com.otv.cache.service.CacheService">
        <property name="userMap" ref="UserMap"/>
    </bean>   
 
    <bean id="RMIUserService" class="com.otv.rmi.server.RMIUserService" >
        <property name="cacheService" ref="CacheService"/>
    </bean>
 
    <!-- RMI Server Declaration -->
    <bean class="org.springframework.remoting.rmi.RmiServiceExporter">
 
        <!-- serviceName represents RMI Service Name -->
        <property name="serviceName" value="RMIUserService"/>
 
        <!-- service represents RMI Object(RMI Service Impl) -->
        <property name="service" ref="RMIUserService"/>
 
        <!-- serviceInterface represents RMI Service Interface exposed -->
        <property name="serviceInterface" value="com.otv.rmi.server.IRMIUserService"/>
 
        <!-- defaults to 1099 -->
        <property name="registryPort" value="1099"/>
 
   </bean>
 
</beans>

STEP 10 : CREATE RMIServiceClient CLASS

RMIServiceClient Class is created. It calls the RMI User Service and performs user operations.

package com.otv.rmi.client;
 
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
import com.otv.rmi.server.IRMIUserService;
import com.otv.rmi.server.RMIUserService;
import com.otv.user.User;
 
/**
 * RMI Service Client
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class RMIServiceClient {
 
    private static Logger logger = Logger.getLogger(RMIUserService.class);
 
    /**
     * Main method of the RMI Service Client
     *
     */
    public static void main(String[] args) {
 
        logger.debug("RMI Service Client is starting...");
 
        //RMI Client Application Context is started...
        ApplicationContext context = new ClassPathXmlApplicationContext("rmiClientAppContext.xml");
 
        //Remote User Service is called via RMI Client Application Context...
        IRMIUserService rmiClient = (IRMIUserService) context.getBean("RMIUserService");
 
        //New User is created...
        User user = new User();
        user.setId(1);
        user.setName("Bruce");
        user.setSurname("Willis");
 
        //The user is added to the remote cache...
        rmiClient.addUser(user);
 
        //The users are gotten via remote cache...
        rmiClient.getUserList();
 
        //The user is deleted from remote cache...
        rmiClient.deleteUser(user);
 
        logger.debug("RMI Service Client is stopped...");
    }
}

STEP 11 : CREATE rmiClientAppContext.xml

RMI Client Application Context’ s content is shown as below.

<beans xmlns="http://www.springframework.org/schema/beans"
    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">
 
    <!-- RMI Client Declaration -->
    <bean id="RMIUserService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
 
        <!-- serviceUrl represents RMI Service Url called-->
        <property name="serviceUrl" value="rmi://x.x.x.x:1099/RMIUserService"/>
 
        <!-- serviceInterface represents RMI Service Interface called -->
        <property name="serviceInterface" value="com.otv.rmi.server.IRMIUserService"/>
 
        <!-- refreshStubOnConnectFailure enforces automatic re-lookup of the stub if a
                            call fails with a connect exception -->
        <property name="refreshStubOnConnectFailure" value="true"/>
 
    </bean>
 
</beans>

STEP 12 : RUN PROJECT

If RMI Service Client is started when RMI Server runs, below RMI Server output logs will be shown. Also, RMI Server and Client can be run by opening two seperate consoles via your IDE. :

....
04.03.2012 14:23:15 DEBUG (RmiBasedExporter.java:59) - RMI service [com.otv.rmi.server.RMIUserService@16dadf9] is an RMI invoker
04.03.2012 14:23:15 DEBUG (JdkDynamicAopProxy.java:113) - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.otv.rmi.server.RMIUserService@16dadf9]
04.03.2012 14:23:15  INFO (RmiServiceExporter.java:276) - Binding service 'RMIUserService' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[192.168.1.7:1099](local),objID:[0:0:0, 0]]]]
04.03.2012 14:23:15 DEBUG (AbstractAutowireCapableBeanFactory.java:458) - Finished creating instance of bean 'org.springframework.remoting.rmi.RmiServiceExporter#0'
04.03.2012 14:23:15 DEBUG (AbstractApplicationContext.java:845) - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@3c0007]
04.03.2012 14:23:15 DEBUG (AbstractBeanFactory.java:245) - Returning cached instance of singleton bean 'lifecycleProcessor'
 
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.addUser
04.03.2012 14:25:43 DEBUG (RMIUserService.java:33) - User has been added to cache. User : Id : 1, Name : Bruce, Surname : Willis
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.addUser
 
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
04.03.2012 14:25:43 DEBUG (RMIUserService.java:57) - User List : [Id : 1, Name : Bruce, Surname : Willis]
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
 
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.deleteUser
04.03.2012 14:25:43 DEBUG (RMIUserService.java:45) - User has been deleted from cache. User : Id : 1, Name : Bruce, Surname : Willis
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.deleteUser
 
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:73) - Incoming RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList
04.03.2012 14:25:43 DEBUG (RMIUserService.java:57) - User List : []
04.03.2012 14:25:43 DEBUG (RemoteInvocationTraceInterceptor.java:79) - Finished processing of RmiServiceExporter remote call: com.otv.rmi.server.IRMIUserService.getUserList

STEP 13 : DOWNLOAD

OTV_SpringRMI

Reference: Spring Remoting Support and Developing RMI Service from our JCG partner Eren Avsarogullari at the Online Technology Vision blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Dimitris
12 years ago

Hello, thanks for the article.

I’m sure it is a typo because otherwise the code wouldn’t compile: the generic type signature of ConcurrentHashMap is obviously wrong. It rather needs to be: ConcurrentHashMap

Back to top button