com.healthmarketscience.rmiio.RemoteWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.healthmarketscience.rmiio.RemoteWrapper.java

Source

/*
 * 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 info@healthmarketscience.com
 * 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 <b>idempotent</b> method calls. See {@link RemoteInputStreamWrapper} and {@link RemoteOutputStreamWrapper} for example usage.
 * <p>
 * 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<RemoteType> implements InvocationHandler, RemoteClient {

    /**
     * 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 a proxy for the given interface using the given retry strategy
     */
    public static <R> R wrap(Class<R> iface, R stub, RemoteRetry retry, Log log) {
        RemoteWrapper<R> wrapper = new RemoteWrapper<R>(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 getRemoteRetry() {
        return _retry;
    }

    /**
     * {@inheritDoc}
     * <p>
     * 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).
     * <p>
     * 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 setRemoteRetry(RemoteRetry retry) {
        _retry = ((retry != null) ? retry : DEFAULT_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<Object>() {
            @Override
            public Object call() throws Exception {
                return method.invoke(_stub, method, args);
            }
        }, _log, Exception.class);
    }

}