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 }