/** * Yields a result for elements of the cross product of the underlying Try. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function<? super T1, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.map(f); }
@Override default <U> Future<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return transformValue(t -> t.map(mapper)); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(BiFunction<? super T1, ? super T2, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.map(t2 -> f.apply(t1, t2))); }
/** * Collects value that is in the domain of the given {@code partialFunction} by mapping the value to type {@code R}. * * <pre>{@code * partialFunction.isDefinedAt(value) * }</pre> * * If the element makes it through that filter, the mapped instance is wrapped in {@code Try} * * <pre>{@code * R newValue = partialFunction.apply(value) * }</pre> * * * @param partialFunction A function that is not necessarily defined on value of this try. * @param <R> The new value type * @return A new {@code Try} instance containing value of type {@code R} * @throws NullPointerException if {@code partialFunction} is null */ @SuppressWarnings("unchecked") default <R> Try<R> collect(PartialFunction<? super T, ? extends R> partialFunction){ Objects.requireNonNull(partialFunction, "partialFunction is null"); return filter(partialFunction::isDefinedAt).map(partialFunction::apply); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function3<? super T1, ? super T2, ? super T3, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.map(t3 -> f.apply(t1, t2, t3)))); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function4<? super T1, ? super T2, ? super T3, ? super T4, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.flatMap(t3 -> ts4.map(t4 -> f.apply(t1, t2, t3, t4))))); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function5<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.flatMap(t3 -> ts4.flatMap(t4 -> ts5.map(t5 -> f.apply(t1, t2, t3, t4, t5)))))); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function6<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.flatMap(t3 -> ts4.flatMap(t4 -> ts5.flatMap(t5 -> ts6.map(t6 -> f.apply(t1, t2, t3, t4, t5, t6))))))); }
/** * Returns a this and that Future result combined using a given combinator function. * <p> * If this Future failed the result contains this failure. Otherwise the result contains that failure or * a combination of both successful Future results. * * @param that Another Future * @param combinator The combinator function * @param <U> Result type of {@code that} * @param <R> Result type of {@code f} * @return A new Future that returns both Future results. * @throws NullPointerException if {@code that} is null */ @SuppressWarnings({"deprecation", "unchecked"}) default <U, R> Future<R> zipWith(Future<? extends U> that, BiFunction<? super T, ? super U, ? extends R> combinator) { Objects.requireNonNull(that, "that is null"); Objects.requireNonNull(combinator, "combinator is null"); return run(executor(), complete -> onComplete(res1 -> { if (res1.isFailure()) { complete.with((Try.Failure<R>) res1); } else { that.onComplete(res2 -> { final Try<R> result = res1.flatMap(t -> res2.map(u -> combinator.apply(t, u))); complete.with(result); }); } }) ); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function7<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? super T7, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.flatMap(t3 -> ts4.flatMap(t4 -> ts5.flatMap(t5 -> ts6.flatMap(t6 -> ts7.map(t7 -> f.apply(t1, t2, t3, t4, t5, t6, t7)))))))); }
@Test public void decorateFunction() throws Exception { Function<Integer, String> function = mock(Function.class); Function<Integer, String> decorated = RateLimiter.decorateFunction(limit, function); when(limit.getPermission(config.getTimeoutDuration())) .thenReturn(false); Try<String> decoratedFunctionResult = Try.success(1).map(decorated); then(decoratedFunctionResult.isFailure()).isTrue(); then(decoratedFunctionResult.getCause()).isInstanceOf(RequestNotPermitted.class); verify(function, never()).apply(any()); when(limit.getPermission(config.getTimeoutDuration())) .thenReturn(true); Try secondFunctionResult = Try.success(1).map(decorated); then(secondFunctionResult.isSuccess()).isTrue(); verify(function, times(1)).apply(1); }
@Test public void decorateSupplier() throws Exception { Supplier supplier = mock(Supplier.class); Supplier decorated = RateLimiter.decorateSupplier(limit, supplier); when(limit.getPermission(config.getTimeoutDuration())) .thenReturn(false); Try decoratedSupplierResult = Try.success(decorated).map(Supplier::get); then(decoratedSupplierResult.isFailure()).isTrue(); then(decoratedSupplierResult.getCause()).isInstanceOf(RequestNotPermitted.class); verify(supplier, never()).get(); when(limit.getPermission(config.getTimeoutDuration())) .thenReturn(true); Try secondSupplierResult = Try.success(decorated).map(Supplier::get); then(secondSupplierResult.isSuccess()).isTrue(); verify(supplier, times(1)).get(); }
/** * Yields a result for elements of the cross product of the underlying Trys. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function8<? super T1, ? super T2, ? super T3, ? super T4, ? super T5, ? super T6, ? super T7, ? super T8, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.flatMap(t1 -> ts2.flatMap(t2 -> ts3.flatMap(t3 -> ts4.flatMap(t4 -> ts5.flatMap(t5 -> ts6.flatMap(t6 -> ts7.flatMap(t7 -> ts8.map(t8 -> f.apply(t1, t2, t3, t4, t5, t6, t7, t8))))))))); }
@Test public void shouldInvokeMap() { // tag::shouldInvokeMap[] // Given CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("testName"); // When I decorate my function CheckedFunction0<String> decoratedSupplier = CircuitBreaker .decorateCheckedSupplier(circuitBreaker, () -> "This can be any method which returns: 'Hello"); // and chain an other function with map Try<String> result = Try.of(decoratedSupplier) .map(value -> value + " world'"); // Then the Try Monad returns a Success<String>, if all functions ran successfully. assertThat(result.isSuccess()).isTrue(); assertThat(result.get()).isEqualTo("This can be any method which returns: 'Hello world'"); // end::shouldInvokeMap[] }
@Test public void shouldInvokeMap() { // tag::shouldInvokeMap[] // Given Bulkhead bulkhead = Bulkhead.of("testName", config); // When I decorate my function CheckedFunction0<String> decoratedSupplier = Bulkhead.decorateCheckedSupplier(bulkhead, () -> "This can be any method which returns: 'Hello"); // and chain an other function with map Try<String> result = Try.of(decoratedSupplier) .map(value -> value + " world'"); // Then the Try Monad returns a Success<String>, if all functions ran successfully. assertThat(result.isSuccess()).isTrue(); assertThat(result.get()).isEqualTo("This can be any method which returns: 'Hello world'"); assertThat(bulkhead.getMetrics().getAvailableConcurrentCalls()).isEqualTo(1); // end::shouldInvokeMap[] }
@Test public void shouldThrowCircuitBreakerOpenException() { // tag::shouldThrowCircuitBreakerOpenException[] // Given CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom() .ringBufferSizeInClosedState(2) .waitDurationInOpenState(Duration.ofMillis(1000)) .build(); CircuitBreaker circuitBreaker = CircuitBreaker.of("testName", circuitBreakerConfig); // Simulate a failure attempt circuitBreaker.onError(0, new RuntimeException()); // CircuitBreaker is still CLOSED, because 1 failure is allowed assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.CLOSED); // Simulate a failure attempt circuitBreaker.onError(0, new RuntimeException()); // CircuitBreaker is OPEN, because the failure rate is above 50% assertThat(circuitBreaker.getState()).isEqualTo(CircuitBreaker.State.OPEN); // When I decorate my function and invoke the decorated function Try<String> result = Try.of(CircuitBreaker.decorateCheckedSupplier(circuitBreaker, () -> "Hello")) .map(value -> value + " world"); // Then the call fails, because CircuitBreaker is OPEN assertThat(result.isFailure()).isTrue(); // Exception is CircuitBreakerOpenException assertThat(result.failed().get()).isInstanceOf(CircuitBreakerOpenException.class); // end::shouldThrowCircuitBreakerOpenException[] CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics(); assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(2); }
/** * Yields a result for elements of the cross product of the underlying Try. * * @param f a function that maps an element of the cross product to a result * @param <R> type of the resulting {@code Try} elements * @return an {@code Try} of mapped results */ public <R> Try<R> yield(Function<? super T1, ? extends R> f) { Objects.requireNonNull(f, "f is null"); return ts1.map(f); }
@Override default <U> Future<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); return transformValue(t -> t.map(mapper)); }
private static <O> Either<Throwable, O> execute(final Supplier<O> operation) { LOGGER.trace("Will execute {}.", operation); return Try.ofSupplier(operation).map(Either::<Throwable, O>right) .recover(t -> { LOGGER.debug("Operation failed.", t); return Either.left(t); }).get(); }