Skip to content

Instantly share code, notes, and snippets.

@pholser
Created October 26, 2015 19:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pholser/38de784fc58dcdabb1ee to your computer and use it in GitHub Desktop.
Save pholser/38de784fc58dcdabb1ee to your computer and use it in GitHub Desktop.
Dressed up old factory bean in Java >= 7 clothes
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