All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.healthmarketscience.rmiio.RemoteWrapper Maven / Gradle / Ivy

There is a newer version: 2.1.2
Show newest version
/*
Copyright (c) 2007 Health Market Science, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
USA

You can contact Health Market Science at [email protected]
or at the following address:

Health Market Science
2700 Horizon Drive
Suite 200
King of Prussia, PA 19406
*/

package com.healthmarketscience.rmiio;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import java.lang.reflect.Proxy;


/**
 * Base class for implementing remote stub wrappers with builtin retry
 * policies.  Providers of remote interfaces can generate simple wrappers for
 * use by a remote client which handle the retry functionality under the hood,
 * simplifying client code dramatically.  Note that this should only be done
 * for idempotent method calls. See {@link RemoteInputStreamWrapper}
 * and {@link RemoteOutputStreamWrapper} for example usage.
 * 

* While subclassing presents an ability to fine tune the wrapper * implementation, it may be difficult and/or unnecessary for many interfaces. * In that case, a much simpler wrapper can be created using the {@link #wrap} * method, which uses the java {@code Proxy} functionality to generate the * wrapper implementation at run time. This may be slightly less efficient * than a custom implementation since reflection is used for the actual method * invocations, but for remote method calls that overhead is probably * meaningless. * * @author James Ahlborn */ public class RemoteWrapper implements InvocationHandler { /** the handle to the remote interface which will do the real work of the remote method calls */ protected final RemoteType _stub; /** the retry policy we are using for our remote calls */ protected RemoteRetry _retry; /** the log which will be used by the retry facility when making the remote calls */ protected final Log _log; public RemoteWrapper(RemoteType stub, RemoteRetry retry, Log log) { _stub = stub; _retry = retry; _log = log; } /** * Simple wrapper generator which creates a Proxy for the given remote * interface. This proxy will make all the remote calls through the * {@link #invoke} method which makes the actual method calls on the * underlying stub within the retry logic. * * @param iface the remote interface to be implemented * @param stub the underlying implementation of the remote interface which * will actually make the remote calls * @param retry the retry policy to use for the remote calls * @param log the log to use during retry handling * * @return */ public static R wrap(Class iface, R stub, RemoteRetry retry, Log log) { RemoteWrapper wrapper = new RemoteWrapper(stub, retry, log); return iface.cast(Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), new Class[]{iface}, wrapper)); } /** * Gets the wrapper underlying a proxy created by a call to {@link #wrap}. */ public static RemoteWrapper getWrapper(Object proxy) { return (RemoteWrapper)Proxy.getInvocationHandler(proxy); } public RemoteType getStub() { return _stub; } public Log getLog() { return _log; } public RemoteRetry getRetry() { return _retry; } /** * Sets the retry policy for this wrapper. This may be useful for * temporarily changing the retry policy for a specific set of calls (e.g. a * startup/discovery sequence may be more forgiving than normal usage). *

* Note, this method is not thread-safe as this should only be used on a * wrapper for which the caller has exclusive ownership (the retry policy * will be changed for all users of the wrapper). */ public void setRetry(RemoteRetry retry) { _retry = retry; } public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable { // make the method call on the actual remote stub within the retry handler return _retry.call(new RemoteRetry.Caller() { @Override public Object call() throws Exception { return method.invoke(_stub, method, args); } }, _log, Exception.class); } }