This
lightweight, Spring-friendly, broker independent library provides a
simple way to make remote calls via JMS API, allows RMI over JMS. The
library supports synchronous and asynchronous remote method invocations
as well as remote callbacks and remote exception handing.
Once you download the
archive with the library you will find everything you need to compile
it and use: sources, third-party jars, build.properties and build.xml
files. The usage principals and setup is pretty similar to the Spring
remoting or Lingo use. You simply put in the Spring application context
all definitions like those shown below.
The remote method is considered as a synchronous if it returns
a value and/or it throws an exception. This way the client code will wait for
the remote result or an exception to be passed from the server side taking into
account the timeout value. If the
method doesn’t return any value and it does not throw any exception it
is
considered
as
asynchronous
and
will
be called asynchronously.
If the method argument is an instance of java.util.EventListener
or java.rmi.Remote
type it will be sent to the server side as a special remote delegate containing
an identifier of the real object on the client side. Being passed to the server
side it turns into a proxy delegating all the method calls back to the client
side's object that it represents remotely.
It’s also important to take into account that the listener
object you pass to the client side as an argument turns into a dynamic proxy
so the methods like equals and hashCode are not implemented except your remote
object implements these methods.
A reference to the remote listener on the client side as well
as to a proxy object on the server side are held as a weak reference and it's
a programmer's responsibility to keep an object alive. On the server side it's
just a matter of performance because it acts as a simple cache and destroyed
objects can cause just a repetitive creation of new proxies as overhead costs.
But for the client side it can lead to a serious problem because a server's calls
will refer to non-existent objects.
All methods are called by names and so a method overloading
is not supported from considerations of performance.
Here is the usage example (taken from examples):
AbstractApplicationContext ctx =
new ClassPathXmlApplicationContext ("context.xml");
// ########################################
// CLIENT SIDE CODE
// ########################################
MathService helper = (MathService)ctx.getBean ("client");
//// YOUR CODE HERE
ctx.destroy (); |
There's an example configuration file of both client
and server sides here (taken from examples):
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Server side -->
<bean id="server" class="org.jmsrmi.spring.RemoteServiceProviderBean">
<property name="connectionFactory" ref="jmsFactory"/>
<property name="serviceDestination" ref="destination"/>
<property name="service" ref="serviceImpl"/>
</bean>
<!-- Client side -->
<bean id="client" class="org.jmsrmi.spring.RemoteServiceConsumerFactory">
<property name="connectionFactory" ref="jmsFactory"/>
<property name="serviceDestination" ref="destination"/>
<property name="serviceInterface" value="org.jmsrmi.test.MathService"/>
</bean>
<!-- Service implementation -->
<bean id="serviceImpl" class="org.jmsrmi.test.MathServiceImpl" singleton="true"/>
<!-- JMS connection factory -->
<bean id="jmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<!-- JMS destination -->
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="MathService"/>
</bean>
</beans> |
It's also possible to use this library without Spring
(taken from examples):
|
ConnectionFactory cf = new ActiveMQConnectionFactory (
"vm://localhost?broker.persistent=false");
// ########################################
// SERVER SIDE CODE
// ########################################
RemoteServiceProvider rsp = new RemoteServiceProvider (
cf, new MathServiceImpl (), new ActiveMQQueue ("MathService"));
// ########################################
// CLIENT SIDE CODE
// ########################################
RemoteServiceConsumer rsc = new RemoteServiceConsumer (
cf, MathService.class, new ActiveMQQueue ("MathService"), 30);
MathService serv = (MathService)rsc.createService ();
//// YOUR CODE HERE
rsc.release ();
rsp.release ();
|
Vitaly Tsaplin, 2007
E-mail: Vitaly.Tsaplin@gmail.com