Created
October 26, 2015 19:12
-
-
Save pholser/38de784fc58dcdabb1ee to your computer and use it in GitHub Desktop.
Dressed up old factory bean in Java >= 7 clothes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.containerstore.common.base.exception.SystemException; | |
import com.google.common.collect.Iterables; | |
import org.aopalliance.intercept.MethodInterceptor; | |
import org.aopalliance.intercept.MethodInvocation; | |
import org.apache.log4j.Logger; | |
import org.springframework.aop.framework.ProxyFactory; | |
import org.springframework.beans.factory.FactoryBean; | |
import org.springframework.remoting.support.RemoteAccessor; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import static com.containerstore.common.thirdparty.log4j.Log4JHelper.*; | |
/** | |
* Adapted from | |
* <a href="http://agilearchitect.blogspot.com/2006/02/failover-mechansim-using-spring.html">this post [sic]</a>. | |
*/ | |
public class FailoverProxyFactoryBean<T> | |
extends RemoteAccessor | |
implements MethodInterceptor, FactoryBean<T> { | |
private static final Logger LOG = classLogger(); | |
private static final String FATAL_FAILOVER_MESSAGE = | |
"No service providers could satisfy method [%s] with arguments [%s]." | |
+ " Last attempted service provider [%s] raised exception."; | |
private T serviceProxy; | |
private List<T> serviceProviders = new ArrayList<>(); | |
public Object invoke(MethodInvocation invocation) throws Throwable { | |
List<InvocationTargetException> exceptions = new ArrayList<>(); | |
for (T each : serviceProviders) { | |
try { | |
return invokeService(invocation, each); | |
} catch (InvocationTargetException e) { | |
exceptions.add(e); | |
} | |
} | |
return handleServiceFatality(invocation, exceptions); | |
} | |
public void setServiceProviders(List<T> serviceProviders) { | |
this.serviceProviders.addAll(serviceProviders); | |
} | |
@SuppressWarnings("unchecked") | |
public void afterPropertiesSet() throws Exception { | |
if (getServiceInterface() == null) { | |
throw new IllegalArgumentException("Service interface missing"); | |
} | |
if (serviceProviders.isEmpty()) { | |
throw new IllegalArgumentException("No service providers configured"); | |
} | |
for (T each : serviceProviders) { | |
if (!getServiceInterface().isInstance(each)) { | |
throw new IllegalArgumentException( | |
each.getClass() | |
+ " does not implement the serviceInterface: " | |
+ getServiceInterface()); | |
} | |
} | |
serviceProxy = (T) ProxyFactory.getProxy(getServiceInterface(), this); | |
} | |
public T getObject() { | |
return this.serviceProxy; | |
} | |
public Class<?> getObjectType() { | |
return getServiceInterface(); | |
} | |
public boolean isSingleton() { | |
return true; | |
} | |
private Object invokeService(MethodInvocation invocation, T provider) | |
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { | |
Method method = invocation.getMethod(); | |
debug(LOG, | |
"Invoking method [%s] with arguments [%s] on service provider [%s]", | |
method.getName(), | |
Arrays.asList(invocation.getArguments()), | |
provider); | |
try { | |
return provider.getClass().getMethod(method.getName(), method.getParameterTypes()) | |
.invoke(provider, invocation.getArguments()); | |
} catch (IllegalAccessException | |
| IllegalArgumentException | |
| NoSuchMethodException | |
| SecurityException e) { | |
LOG.error(String.format( | |
"Unexpected exception invoking method [%s] with arguments [%s] on service provider [%s]", | |
method.getName(), | |
Arrays.asList(invocation.getArguments()), | |
provider), e); | |
throw e; | |
} catch (InvocationTargetException e) { | |
LOG.error(String.format( | |
"Exception invoking method [%s] with arguments [%s] on service provider [%s]", | |
method.getName(), | |
Arrays.asList(invocation.getArguments()), | |
provider), e); | |
throw e; | |
} | |
} | |
private Object handleServiceFatality( | |
MethodInvocation invocation, | |
List<InvocationTargetException> exceptions) { | |
InvocationTargetException last = Iterables.getLast(exceptions); | |
LOG.fatal( | |
String.format( | |
FATAL_FAILOVER_MESSAGE, | |
invocation.getMethod().getName(), | |
Arrays.asList(invocation.getArguments()), | |
Iterables.getLast(serviceProviders)), | |
last); | |
throw new SystemException( | |
String.format( | |
FATAL_FAILOVER_MESSAGE, | |
invocation.getMethod().getName(), | |
Arrays.asList(invocation.getArguments()), | |
Iterables.getLast(serviceProviders)), | |
last); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment