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 }