001/** 002 * Powerunit - A JDK1.8 test framework 003 * Copyright (C) 2014 Mathieu Boretti. 004 * 005 * This file is part of Powerunit 006 * 007 * Powerunit is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * Powerunit is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU General Public License for more details. 016 * 017 * You should have received a copy of the GNU General Public License 018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>. 019 */ 020package ch.powerunit.extensions.async.lang; 021 022import java.util.Optional; 023import java.util.concurrent.CancellationException; 024import java.util.concurrent.CompletableFuture; 025import java.util.concurrent.CompletionStage; 026import java.util.concurrent.ExecutionException; 027import java.util.concurrent.TimeUnit; 028import java.util.function.Consumer; 029import java.util.function.Function; 030 031/** 032 * Last Step of the builder of {@link CompletableFuture} to create the 033 * completable operation it self. 034 * 035 * @param <T> 036 * The type of result of the {@link CompletableFuture} 037 * @since 1.0.0 038 */ 039public interface WaitResultBuilder6<T> { 040 041 /** 042 * Create and start the async execution of the {@link CompletableFuture} the 043 * executor that was defined before. 044 * <p> 045 * This method is the <i>main</i> method of this interface. This start the 046 * execution of the {@link CompletableFuture} based on the parameter defined 047 * before. 048 * <p> 049 * For example: 050 * 051 * <pre> 052 * CompletableFuture<Optional<String>> future = WaitResult.of(myCallable).dontIgnoreException() 053 * .expecting(myPredicate).repeat(2).every(1000, TimeUnit.MILLISECONDS).usingDefaultExecutor().asyncExec(); 054 * </pre> 055 * 056 * This defines a {@link CompletableFuture} that will repeat maximum two time, 057 * with a wait time of 1000ms, the execution of {@code myCallable}, doesn't 058 * ignore the exception, verify the {@code myPredicate} condition. This 059 * {@link CompletableFuture} will use the default executor. 060 * 061 * @return the {@link CompletableFuture} 062 */ 063 CompletableFuture<Optional<T>> asyncExec(); 064 065 /** 066 * Directly wait for the result of this execution. In case of not ignored 067 * exception, an {@link AssertionError} is thrown. 068 * <p> 069 * This method is a <i>shortcut</i> method to {@code asyncExec().get()}, which 070 * throw AssertionError in case of error. 071 * 072 * @return the {@link Optional} with the result of the execution 073 * 074 * @throws AssertionError 075 * In case of not ignored exception. 076 * @see #asyncExec() 077 * @see CompletableFuture#get() 078 */ 079 default Optional<T> finish() { 080 try { 081 return asyncExec().get(); 082 } catch (InterruptedException | ExecutionException e) { 083 throw Optional.ofNullable(e.getCause()).filter(c -> c instanceof AssertionError) 084 .map(AssertionError.class::cast) 085 .orElseGet(() -> new AssertionError("Unexpected error " + e.getMessage(), e)); 086 } 087 } 088 089 /** 090 * Directly wait for a positive result of this execution. In case of not ignored 091 * exception, or when no result are available, an {@link AssertionError} is 092 * thrown. 093 * <p> 094 * This method is a <i>shortcut</i> method to the finish method that read the 095 * optional value and throw an AssertionError in case of mission value. 096 * 097 * @return the value if available 098 * 099 * @throws AssertionError 100 * In case of not ignored exception or missing result. 101 * @see #finish() 102 */ 103 default T finishWithAResult() { 104 return finish().orElseThrow(() -> new AssertionError("No result is available")); 105 } 106 107 /** 108 * Shortcut method to the join of the {@link CompletableFuture}. 109 * <p> 110 * Only runtime exception in case of error. 111 * 112 * @return the result of the wait 113 * @since 1.0.0 114 * @see CompletableFuture#join() 115 * @see #asyncExec() 116 */ 117 default Optional<T> join() { 118 return asyncExec().join(); 119 } 120 121 /** 122 * Shortcut method to the join of the {@link CompletableFuture}, that expect a 123 * positive result. 124 * <p> 125 * Only runtime exception in case of error. 126 * 127 * @return the result of the wait 128 * @since 1.0.0 129 * @see CompletableFuture#join() 130 * @see #join() 131 */ 132 default T joinWithAResult() { 133 return join().orElseThrow(() -> new AssertionError("No result is available when one is expected")); 134 } 135 136 /** 137 * Create and start the async execution of the {@link CompletableFuture} and 138 * directly register a Consumer on the result. 139 * 140 * @param action 141 * the action to be done on the result 142 * @return the {@link CompletableFuture} 143 * @since 1.0.0 144 * @see CompletableFuture#thenAccept(Consumer) 145 * @see #asyncExec() 146 */ 147 default CompletableFuture<Void> thenAccept(Consumer<? super Optional<T>> action) { 148 return asyncExec().thenAccept(action); 149 } 150 151 /** 152 * Create and start the async execution of the {@link CompletableFuture} and 153 * directly register a Function on the result. 154 * 155 * @param fn 156 * then function to be applied 157 * 158 * @param <U> 159 * The new return type 160 * @return the {@link CompletableFuture} 161 * @since 1.0.0 162 * @see CompletableFuture#thenApply(Function) 163 * @see #asyncExec() 164 */ 165 default <U> CompletableFuture<U> thenApply(Function<? super Optional<T>, ? extends U> fn) { 166 return asyncExec().thenApply(fn); 167 } 168 169 /** 170 * Create and start the async execution of the {@link CompletableFuture} and 171 * exceptionally completes this CompletableFuture with a TimeoutException if not 172 * otherwise completed before the given timeout. 173 * <p> 174 * <b>Only available on java 9</b> 175 * 176 * @param timeout 177 * how long to wait before completing exceptionally with a 178 * TimeoutException, in units of unit 179 * @param unit 180 * a TimeUnit determining how to interpret the timeout parameter 181 * @return the {@link CompletableFuture} 182 * @since 1.0.0 183 * @see CompletableFuture#orTimeout(long, TimeUnit) 184 * @see #asyncExec() 185 */ 186 default CompletableFuture<Optional<T>> orTimeout(long timeout, TimeUnit unit) { 187 throw new UnsupportedOperationException("Not available on java 8"); 188 } 189 190 /** 191 * Returns a new CompletionStage that is completed normally based on this 192 * {@link CompletableFuture}. 193 * <p> 194 * <b>Only available on java 9</b> 195 * 196 * @return the new CompletionStage 197 * @since 1.0.0 198 * @see CompletableFuture#minimalCompletionStage() 199 * @see #asyncExec() 200 */ 201 default CompletionStage<Optional<T>> minimalCompletionStage​() { 202 throw new UnsupportedOperationException("Not available on java 8"); 203 } 204 205 /** 206 * Waits if necessary for the produced future to complete, and then returns its 207 * result. 208 * 209 * @return the result value 210 * @throws CancellationException 211 * if the produced future was cancelled 212 * @throws ExecutionException 213 * if the produced future completed exceptionally 214 * @throws InterruptedException 215 * if the current thread was interrupted while waiting 216 * @see CompletableFuture#get() 217 * @see #asyncExec() 218 * @since 1.0.0 219 */ 220 default Optional<T> get() throws InterruptedException, ExecutionException { 221 return asyncExec().get(); 222 } 223}