RemoteServiceProvider.java from Texai at Krugle
Show RemoteServiceProvider.java syntax highlighted
/*
* RemoteServiceProvider.java
*
* Created on April 24, 2007, 1:37 PM
*
* Description: Provides a remote service provider.
*
* Copyright (C) April 24, 2007 Stephen L. Reed, ported to ApacheMQ and derived from
* substantially the same class written by Vitaly Tsaplin, 2007, http://jmsrmi.sourceforge.net/
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.texai.kb.ejb.jmsrmi;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import org.apache.log4j.Logger;
import org.texai.util.TexaiException;
/**
* @author vtsaplin
*
*/
public class RemoteServiceProvider implements MessageListener {
/** the logger */
private static final Logger LOGGER = Logger.getLogger(RemoteServiceProvider.class);
/** the JMS connection factory */
private ConnectionFactory connectionFactory;
/** the JMS connection */
private Connection connection;
/** the service destination */
private Destination serviceDestination;
/** the JMS session */
private Session session;
/** the message producer */
private MessageProducer producer;
/** the message consumer */
private MessageConsumer consumer;
/** the transferred objects cache */
private final Map<Long, Object> cache;
/** the service */
private Object service;
/** the method cache */
private final Map<String, Method> methodDictionary = new HashMap<String, Method>();
/** Creates a new RemoteServiceProvider instance. */
public RemoteServiceProvider() {
cache = Collections.synchronizedMap(new WeakHashMap<Long, Object> ());
}
/** Gets the service.
*
* @return the service
*/
public Object getService() {
return service;
}
/** Sets the service.
*
* @param service the service
*/
public void setService(final Object service) {
//Preconditions
assert service != null : "service must not be null";
this.service = service;
}
/** Gets the JMS connection factory
*
* @return the JMS connection factory
*/
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
/** Sets the JMS connection factory.
*
* @param connectionFactory the JMS connection factory
*/
public void setConnectionFactory(final ConnectionFactory connectionFactory) {
//Preconditions
assert connectionFactory != null : "connectionFactory must not be null";
this.connectionFactory = connectionFactory;
}
/** Gets the service destination.
*
* @return the service destination
*/
public Destination getServiceDestination() {
return serviceDestination;
}
/** Sets the service destination.
*
* @param serviceDestination the service destination
*/
public void setServiceDestination(final Destination serviceDestination) {
this.serviceDestination = serviceDestination;
}
/** Initializes this remote service provider. */
public void init() throws Exception {
try {
// Create a connection.
connection = connectionFactory.createConnection();
connection.start();
// Create a session.
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create a consumer to receive remote method invocation requests.
consumer = session.createConsumer(serviceDestination);
consumer.setMessageListener(this);
// Create a producer for sending returned values and callback invocations.
producer = session.createProducer(null);
} catch (final JMSException ex) {
throw new TexaiException(ex);
}
}
/** Cleans up this remote service provider. */
public void cleanup() throws Exception {
try {
consumer.close();
session.close();
connection.close();
} catch (final JMSException ex) {
throw new TexaiException(ex);
}
}
/** Provides a remote listener.
* @author vtsaplin
*
*/
private class RemoteListener implements InvocationHandler {
/** the transfer object id */
private long id;
/** the destination */
private Destination destination;
/** Creates a new RemoteListener instance.
*
* @param id the transfer object id
* @param destination the destination
*/
public RemoteListener(final long id, final Destination destination) {
//Preconditions
assert destination != null : "destination must not be null";
this.id = id;
this.destination = destination;
}
/** Processes a method invocation on a proxy instance and returns the result.
*
* @param proxy the proxy instance that the method was invoked on
* @param method the Method instance corresponding to the interface method invoked on the proxy instance
* @param args an array of objects containing the values of the arguments passed in the method invocation
* on the proxy instance, or null if interface method takes no arguments
*/
public Object invoke(
final Object proxy,
final Method method,
final Object [] args) throws Throwable {
LOGGER.debug("invoking " + method.getName());
final RemoteInvocation remoteInvocation = new RemoteInvocation(id, method, args);
producer.send(destination, session.createObjectMessage(remoteInvocation));
return null;
}
}
/** Passes a message to the listener.
*
* @param msg the JMS message
*/
public void onMessage(final Message msg) {
LOGGER.debug("onMessage " + msg);
try {
if (msg instanceof ObjectMessage) {
final Object obj = ((ObjectMessage)msg).getObject();
if (RemoteInvocation.class.equals(obj.getClass())) {
final RemoteInvocation remoteInvocation = (RemoteInvocation)((ObjectMessage)msg).getObject();
Object result = null;
final String methodName = remoteInvocation.getName();
Method method = methodDictionary.get(methodName);
if (method == null) {
for (final Method serviceMethod : service.getClass().getMethods()) {
if (serviceMethod.getName().equals(methodName)) {
method = serviceMethod;
methodDictionary.put(methodName, method);
break;
}
}
}
assert method != null : "cannot find service method for " + msg;
final Object[] args = remoteInvocation.getArgs();
if (args != null) {
for (int i = 0; i < args.length; i++) {
if (RemoteInvocationArgument.class.equals(args[i].getClass())) {
final RemoteInvocationArgument remoteInvocationArgument = (RemoteInvocationArgument)args[i];
if (cache.containsKey(remoteInvocationArgument.getID())) {
// we use a proxy from the cache
args[i] = cache.get(remoteInvocationArgument.getID());
} else {
// create a new proxy for a remote calback method
args [i] = Proxy.newProxyInstance(
getClass().getClassLoader(),
remoteInvocationArgument.getType().getInterfaces(),
new RemoteListener(remoteInvocationArgument.getID(), msg.getJMSReplyTo()));
// put a newly created proxy to the cache
cache.put(remoteInvocationArgument.getID(), args[i]);
}
}
}
}
// call the method
try {
LOGGER.debug("invoking " + methodName);
result = method.invoke(service, args);
} catch (IllegalArgumentException ex) {
throw new TexaiException(ex);
} catch (InvocationTargetException ex) {
result = ex.getTargetException();
} catch (IllegalAccessException ex) {
throw new TexaiException(ex);
}
if (result != null) {
// we send the result of an invocation back to the client
final RemoteInvocationResult remoteInvocationResult = new RemoteInvocationResult(remoteInvocation.getID(), result);
producer.send(
msg.getJMSReplyTo(),
session.createObjectMessage((Serializable)remoteInvocationResult));
}
}
}
} catch (JMSException ex) {
throw new TexaiException(ex);
}
}
}
See more files for this project here