Skip to content

Commit

Permalink
Added more javadoc
Browse files Browse the repository at this point in the history
  • Loading branch information
patwlan committed Feb 8, 2018
1 parent 3c867ed commit a8b49b1
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 25 deletions.

This file was deleted.

Expand Up @@ -16,6 +16,8 @@
*/
package io.github.resilience4j.feign;

import static java.util.Objects.requireNonNull;

import java.lang.reflect.Method;

import feign.InvocationHandlerFactory.MethodHandler;
Expand All @@ -30,25 +32,23 @@ class FallbackDecorator<T> implements FeignDecorator {
private final T fallback;

public FallbackDecorator(T fallback) {
this.fallback = fallback;
this.fallback = requireNonNull(fallback, "Fallback cannot be null!");
}

/**
* Calls the fallback if the invocationCall throws an {@link Exception}.
*
* @throws IllegalArgumentException if the fallback object does not have a corresponding
* fallback method.
*/
@Override
public CheckedFunction1<Object[], Object> decorate(CheckedFunction1<Object[], Object> invocationCall,
Method method,
MethodHandler methodHandler,
Target<?> target) {
Method fallbackMethod;
try {
fallbackMethod = fallback.getClass().getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException | SecurityException e) {
throw new DecoratorException("Cannot use the fallback ["
+ fallback.getClass() + "] for ["
+ method.getDeclaringClass() + "]", e);
}
final Method fallbackMethod;
validateFallback(method);
fallbackMethod = getFallbackMethod(method);
return args -> {
try {
return invocationCall.apply(args);
Expand All @@ -58,4 +58,24 @@ public CheckedFunction1<Object[], Object> decorate(CheckedFunction1<Object[], Ob
};
}

private void validateFallback(Method method) {
if (fallback.getClass().isAssignableFrom(method.getDeclaringClass())) {
throw new IllegalArgumentException("Cannot use the fallback ["
+ fallback.getClass() + "] for ["
+ method.getDeclaringClass() + "]!");
}
}

private Method getFallbackMethod(Method method) {
Method fallbackMethod;
try {
fallbackMethod = fallback.getClass().getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException | SecurityException e) {
throw new IllegalArgumentException("Cannot use the fallback ["
+ fallback.getClass() + "] for ["
+ method.getDeclaringClass() + "]", e);
}
return fallbackMethod;
}

}
Expand Up @@ -27,9 +27,22 @@
import io.vavr.CheckedFunction1;

/**
* Builder to help build stacked decorators. The order in which decorators are applied correspond to
* the order in which they are declared. For example, calling
* {@link FeignDecorators.Builder#withFallback(Object)} before
* Builder to help build stacked decorators. <br>
*
* <pre>
* {@code
* CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
* RateLimiter rateLimiter = RateLimiter.ofDefaults("backendName");
* FeignDecorators decorators = FeignDecorators.builder()
* .withCircuitBreaker(circuitBreaker)
* .withRateLimiter(rateLimiter)
* .build();
* MyService myService = Resilience4jFeign.builder(decorators).target(MyService.class, "http://localhost:8080/");
* }
* </pre>
*
* The order in which decorators are applied correspond to the order in which they are declared. For
* example, calling {@link FeignDecorators.Builder#withFallback(Object)} before
* {@link FeignDecorators.Builder#withCircuitBreaker(CircuitBreaker)} would mean that the fallback
* is called when the HTTP request fails, but would no longer be reachable if the CircuitBreaker
* were open. However, reversing the order would mean that the fallback is called both when the HTTP
Expand Down Expand Up @@ -62,21 +75,47 @@ public static final class Builder {

private final List<FeignDecorator> decorators = new ArrayList<>();

/**
* Adds a {@link CircuitBreaker} to the decorator chain.
*
* @param rateLimiter a fully configured {@link CircuitBreaker}.
* @return the builder
*/
public Builder withCircuitBreaker(CircuitBreaker circuitBreaker) {
decorators.add((fn, m, mh, t) -> CircuitBreaker.decorateCheckedFunction(circuitBreaker, fn));
return this;
}

/**
* Adds a {@link RateLimiter} to the decorator chain.
*
* @param rateLimiter a fully configured {@link RateLimiter}.
* @return the builder
*/
public Builder withRateLimiter(RateLimiter rateLimiter) {
decorators.add((fn, m, mh, t) -> RateLimiter.decorateCheckedFunction(rateLimiter, fn));
return this;
}

/**
* Adds a fallback to the decorator chain. Multiple fallbacks can be applied with the next
* fallback being called when the previous one fails.
*
* @param fallback must match the feign interface, i.e. the interface specified when calling
* {@link Resilience4jFeign.Builder#target(Class, String)}.
* @return the builder
*/
public Builder withFallback(Object fallback) {
decorators.add(new FallbackDecorator<Object>(fallback));
return this;
}

/**
* Builds the decorator chain. This can then be used to setup an instance of
* {@link Resilience4jFeign}.
*
* @return the decorators.
*/
public FeignDecorators build() {
return new FeignDecorators(decorators);
}
Expand Down
Expand Up @@ -20,8 +20,18 @@
import feign.InvocationHandlerFactory;

/**
* Main class for combining Feign with Resilience4j modules. See {@link FeignDecorators} on how to
* build decorators.
* Main class for combining feign with Resilience4j.
*
* <pre>
* {@code
* MyService myService = Resilience4jFeign.builder(decorators).target(MyService.class, "http://localhost:8080/");
* }
* </pre>
*
* {@link Resilience4jFeign} works in the same way as the standard {@link Feign.Builder}. Only
* {@link Feign.Builder#invocationHandlerFactory(InvocationHandlerFactory)} may not be called as
* this is how {@link Resilience4jFeign} decorates the feign interface. <br>
* See {@link FeignDecorators} on how to build decorators and enhance your feign interfaces.
*/
public final class Resilience4jFeign {

Expand All @@ -37,6 +47,9 @@ public Builder(FeignDecorator invocationDecorator) {
this.invocationDecorator = invocationDecorator;
}

/**
* Will throw an {@link UnsupportedOperationException} exception.
*/
@Override
public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
throw new UnsupportedOperationException();
Expand Down
Expand Up @@ -70,7 +70,7 @@ public void testSuccessful() throws Exception {
verify(1, getRequestedFor(urlPathEqualTo("/greeting")));
}

@Test(expected = DecoratorException.class)
@Test(expected = IllegalArgumentException.class)
public void testInvalidFallback() throws Throwable {
final FeignDecorators decorators = FeignDecorators.builder().withFallback("not a fallback").build();
Resilience4jFeign.builder(decorators).target(TestService.class, MOCK_URL);
Expand Down

0 comments on commit a8b49b1

Please sign in to comment.