001    /*
002     * (c) 2003-2005, 2009, 2010 ThoughtWorks Ltd
003     * All rights reserved.
004     *
005     * The software in this package is published under the terms of the BSD
006     * style license a copy of which has been included with this distribution in
007     * the LICENSE.txt file.
008     * 
009     * Created on 14-May-2004
010     */
011    package com.thoughtworks.proxy.toys.failover;
012    
013    import static com.thoughtworks.proxy.toys.delegate.DelegationMode.DIRECT;
014    
015    import java.lang.reflect.InvocationTargetException;
016    import java.lang.reflect.Method;
017    
018    import com.thoughtworks.proxy.ProxyFactory;
019    import com.thoughtworks.proxy.kit.SimpleReference;
020    import com.thoughtworks.proxy.toys.hotswap.HotSwappingInvoker;
021    
022    /**
023     * {@link com.thoughtworks.proxy.Invoker Invoker} that implements a failover strategy by using different delegates in
024     * case of an exception. The implemented strategy is a simple round-robin algorithm to change the delegate in case of a
025     * relevant exception.
026     *
027     * @author Dan North
028     * @author Aslak Hellesøy
029     * @author Jörg Schaible
030     * @since 0.1
031     */
032    public class FailoverInvoker<T> extends HotSwappingInvoker<T> {
033        private static final long serialVersionUID = -8289095570093619184L;
034        private T[] delegates;
035        private Class<? extends Throwable> exceptionClass;
036        private int current;
037    
038        /**
039         * Construct a FailoverInvoker.
040         *
041         * @param types          the types of the proxy
042         * @param proxyFactory   the {@link ProxyFactory} to use
043         * @param delegates      the delegates to use
044         * @param exceptionClass the type of the exception
045         * @since 0.1
046         */
047        public FailoverInvoker(final Class<?>[] types, final ProxyFactory proxyFactory, final T[] delegates, final Class<? extends Throwable> exceptionClass) {
048            super(types, proxyFactory, new SimpleReference<Object>(delegates[0]), DIRECT);
049            this.delegates = delegates;
050            this.exceptionClass = exceptionClass;
051        }
052    
053        @Override
054        protected Object invokeOnDelegate(final Method method, final Object[] args) throws InvocationTargetException {
055            Object result = null;
056            final int original = current;
057            while (result == null) {
058                try {
059                    result = super.invokeOnDelegate(method, args);
060                    break;
061                } catch (InvocationTargetException e) {
062                    if (exceptionClass.isInstance(e.getTargetException())) {
063                        synchronized (this) {
064                            current++;
065                            current = current % delegates.length;
066                            if (original == current) {
067                                throw e;
068                            }
069                            hotswap(delegates[current]);
070                        }
071                    } else {
072                        throw e;
073                    }
074                }
075            }
076            return result;
077        }
078    }