001 002package io.vrap.rmf.base.client.utils; 003 004import static java.util.stream.Collectors.toList; 005 006import java.time.Duration; 007import java.util.List; 008import java.util.concurrent.*; 009import java.util.function.Function; 010import java.util.stream.Collector; 011import java.util.stream.Collectors; 012import java.util.stream.Stream; 013 014import io.vrap.rmf.base.client.ApiHttpRequest; 015import io.vrap.rmf.base.client.error.RmfTimeoutException; 016 017public class ClientUtils { 018 /** 019 * Waits with a timeout for RESPONSES of a client wrapped in a {@link CompletionStage}. 020 * This method should not be used for other {@link CompletionStage}s since it is throwing {@link io.vrap.rmf.base.client.error.BaseException}s. 021 * 022 * @param completionStage the future monad to wait for 023 * @param request the request belonging to the completionStage 024 * @param duration the maximum duration to wait for this single request 025 * @param <T> type of the result for the request 026 * @return the wrapped value of {@code completionStage} 027 * @throws RmfTimeoutException if a timeout occurs 028 */ 029 public static <T> T blockingWait(final CompletionStage<T> completionStage, final ApiHttpRequest request, 030 final Duration duration) { 031 return blockingWait(completionStage, request, duration.toMillis(), TimeUnit.MILLISECONDS); 032 } 033 034 /** 035 * Waits with a timeout for RESPONSES of a client wrapped in a {@link CompletionStage}. 036 * This method should not be used for other {@link CompletionStage}s since it is throwing {@link io.vrap.rmf.base.client.error.BaseException}s. 037 * 038 * @param completionStage the future monad to wait for 039 * @param duration the maximum duration to wait for this single request 040 * @param <T> type of the result for the request 041 * @return the wrapped value of {@code completionStage} 042 * @throws RmfTimeoutException if a timeout occurs 043 */ 044 public static <T> T blockingWait(final CompletionStage<T> completionStage, final Duration duration) { 045 return blockingWait(completionStage, duration.toMillis(), TimeUnit.MILLISECONDS); 046 } 047 048 /** 049 * Waits with a timeout for RESPONSES of a client wrapped in a {@link CompletionStage}. 050 * This method should not be used for other {@link CompletionStage}s since it is throwing {@link io.vrap.rmf.base.client.error.BaseException}s. 051 * 052 * @param completionStage the future monad to wait for 053 * @param timeout the maximum time to wait for this single request 054 * @param unit the time unit of the timeout argument 055 * @param <T> type of the result for the request 056 * @return the wrapped value of {@code completionStage} 057 * @throws RmfTimeoutException if a timeout occurs 058 */ 059 public static <T> T blockingWait(final CompletionStage<T> completionStage, final long timeout, 060 final TimeUnit unit) { 061 return blockingWait(completionStage, null, timeout, unit); 062 } 063 064 /** 065 * Waits with a timeout for RESPONSES of a client wrapped in a {@link CompletionStage}. 066 * This method should not be used for other {@link CompletionStage}s since it is throwing {@link io.vrap.rmf.base.client.error.BaseException}s. 067 * 068 * @param completionStage the future monad to wait for 069 * @param request the request belonging to the completionStage 070 * @param timeout the maximum time to wait for this single request 071 * @param unit the time unit of the timeout argument 072 * @param <T> type of the result for the request 073 * @return the wrapped value of {@code completionStage} 074 * @throws RmfTimeoutException if a timeout occurs 075 */ 076 public static <T> T blockingWait(final CompletionStage<T> completionStage, final ApiHttpRequest request, 077 final long timeout, final TimeUnit unit) { 078 try { 079 return completionStage.toCompletableFuture().get(timeout, unit); 080 } 081 catch (InterruptedException e) { 082 Thread.currentThread().interrupt(); 083 throw new CompletionException(e); 084 } 085 catch (ExecutionException e) { 086 final Throwable cause = e.getCause() != null ? e.getCause() : e; 087 throw cause instanceof RuntimeException ? (RuntimeException) cause : new CompletionException(cause); 088 } 089 catch (final TimeoutException e) { 090 throw new RmfTimeoutException(e, request); 091 } 092 } 093 094 public static <T> List<T> blockingWaitForEach(final Stream<? extends CompletionStage<T>> stream, 095 final Duration duration) { 096 return blockingWaitForEach(stream, duration.toMillis(), TimeUnit.MILLISECONDS); 097 } 098 099 public static <T> List<T> blockingWaitForEach(final Stream<? extends CompletionStage<T>> stream, final long timeout, 100 final TimeUnit unit) { 101 return stream.map(stage -> blockingWait(stage, timeout, unit)).collect(toList()); 102 } 103 104 public static <T> List<T> blockingWaitForEach(final List<? extends CompletionStage<T>> list, 105 final Duration duration) { 106 return blockingWaitForEach(list, duration.toMillis(), TimeUnit.MILLISECONDS); 107 } 108 109 public static <T> List<T> blockingWaitForEach(final List<? extends CompletionStage<T>> list, final long timeout, 110 final TimeUnit unit) { 111 return blockingWaitForEach(list.stream(), timeout, unit); 112 } 113 114 public static <S extends CompletionStage<T>, T> Collector<S, ?, List<T>> blockingWaitForEachCollector( 115 final long timeout, final TimeUnit unit) { 116 final Function<CompletionStage<T>, T> mapper = stage -> blockingWait(stage, timeout, unit); 117 return Collectors.mapping(mapper, toList()); 118 } 119 120 public static <S extends CompletionStage<T>, T> Collector<S, ?, List<T>> blockingWaitForEachCollector( 121 final Duration duration) { 122 return blockingWaitForEachCollector(duration.toMillis(), TimeUnit.MILLISECONDS); 123 } 124}