FailoverHandlerChain implements FailoverHandler { @Override public <T> Response<T> handle(final Invocation<T> invocation, final Response<T> response) { logger.debug("Handle {} with failover handler chain (handlers: {})", response.getError(), this.failoverHandlers); Response<T> next = response; for (final FailoverHandler failoverHandler : this.failoverHandlers) { if (null == next.getError()) { break; } logger.trace("Handle with {}", failoverHandler); next = failoverHandler.handle(invocation, next); } return next; } FailoverHandlerChain(final List<ComparableFailoverHandler> failoverHandlers); @Override Response<T> handle(final Invocation<T> invocation, final Response<T> response);  }
@Test public void testHandle() { final Set<Object> usedSet = new HashSet<>(); final Object expected = randomUUID().toString(); final ComparableFailoverHandler p1 = new ComparableFailoverHandler() { @Getter protected final int priority = 1; @Override public <T> Response<T> handle(Invocation<T> invocation, Response<T> response) { usedSet.add(this); return response; } }; final ComparableFailoverHandler p2 = new ComparableFailoverHandler() { @Getter protected final int priority = 2; @SuppressWarnings("unchecked") @Override public <T> Response<T> handle(Invocation<T> invocation, Response<T> response) { usedSet.add(this); return (Response<T>) Response.success(expected); } }; final ComparableFailoverHandler p3 = new ComparableFailoverHandler() { @Getter protected final int priority = 3; @Override public <T> Response<T> handle(Invocation<T> invocation, Response<T> response) { fail("Should not run"); return response; } }; final List<ComparableFailoverHandler> failoverHandlers = asList(p2, p3, p1); final FailoverHandlerChain failoverHandlerChain = new FailoverHandlerChain(failoverHandlers); final Response<Object> response = Response.fail(new UnsupportedOperationException()); final Response<Object> handled = failoverHandlerChain.handle(null, response); assertEquals(expected, handled.getValue()); assertEquals(2, usedSet.size()); }