001package Torello.Browser; 002 003import java.util.concurrent.CompletableFuture; 004import java.util.concurrent.CompletionException; 005import java.util.concurrent.ExecutionException; 006import java.util.concurrent.TimeUnit; 007import java.util.concurrent.TimeoutException; 008 009import java.util.function.Function; 010import javax.json.JsonObject; 011 012/** 013 * Primarily a wrapper around Java's {@code CompletableFuture} that provides two or three 014 * simplified methods for <B STYLE='color:red;'><I>awaiting</I></B> a promise. 015 * 016 * <BR /><BR /><EMBED CLASS='external-html' DATA-FILE-ID=PROMISE> 017 * @param <RESULT> <EMBED CLASS='external-html' DATA-FILE-ID=RESULT> 018 */ 019public class Promise<RESULT> extends CompletableFuture<RESULT> 020{ 021 /** The {@link Script} that generated this {@code Promise} */ 022 public final Script<RESULT> script; 023 024 /** 025 * This field will hold the json response which has been recived by the {@code WebSocket's} 026 * layer. This field is assigned immediately preceeding this future's completion. The json 027 * stored here will only be the {@code "result"} property of the surrounding datagram json 028 * envelope. 029 * 030 * <BR /><BR /> 031 * Because CDP may or may not be a "moving target", this field is provided as a manner of 032 * conenience to the developer's wanting to see how their response POJO's were built. In 033 * normal operations, there is likely little use for inspecting the raw protocol json. 034 * 035 * <BR /><BR /><DIV CLASS=JDHint> 036 * This field is updated by the response handler's immediately prior to invoking the 037 * {@code CompletableFuture.complete} method. It is initialized to null. There are also logs 038 * which contain the json that has been sent and received over the WebSocket's layer, although 039 * they are less convenient to use. 040 * </DIV> 041 */ 042 public volatile JsonObject jo = null; 043 044 Promise(final Script<RESULT> script) 045 { this.script = script; } 046 047 String stateToString() 048 { 049 return this.isCompletedExceptionally() 050 ? "already completed with an error." 051 : this.isCancelled() 052 ? "already cancelled." 053 : "already completed."; 054 } 055 056 057 /** 058 * Nearly identical to the {@code CompletableFuture} method {@code join}. 059 * 060 * <BR /><BR /><DIV CLASS=JDHint> 061 * This method is nothing more than a wrapper around the {@code CompletableFuture} method known 062 * as {@code join(long)}. This does a little bit of Exception Unwrapping, as may be viewed in 063 * the Hi-Lited Code, below. 064 * </DIV> 065 * 066 * @return the long-lost, long-awaited-for, result. 067 */ 068 public RESULT await() 069 { 070 try 071 { return this.join(); } 072 073 catch (CompletionException e) 074 { 075 Throwable c = e.getCause(); 076 if (c == null) throw e; 077 if (c instanceof RDPException) throw (RDPException) c; 078 if (c instanceof BrowserException) throw (BrowserException) c; 079 if (c instanceof BrowserErrorException) throw (BrowserErrorException) c; 080 if (c instanceof AsynchronousException) throw (AsynchronousException) c; 081 throw e; 082 } 083 } 084 085 /** 086 * Waits if necessary for at most the given time for this future to complete, and then returns 087 * its result, if available. 088 * 089 * <BR /><BR /><DIV CLASS=JDHint> 090 * This method is nothing more than a wrapper around the {@code CompletableFuture} method known 091 * as {@code get(long, TimeUnit)}. This method simply converts a slew of Checked-Exceptions 092 * into Unchecked / RuntimeExceptions. No more, no less. 093 * </DIV> 094 * 095 * @param timeout The maximum time to wait 096 * @param unit the time unit of the timeout parameter 097 * @return the result value 098 * @throws UncheckedExecutionException if this future completed exceptionally 099 * @throws UncheckedInterruptedException if the current thread was interrupted while waiting 100 * @throws UncheckedTimeoutException if the waiting timed out 101 * @throws CompletionException if this future was cancelled 102 * @throws RDPException 103 * @throws BrowserException 104 * @throws BrowserErrorException 105 * @throws AsynchronousException 106 */ 107 public RESULT await(final long timeout, final TimeUnit unit) 108 { 109 try 110 { return this.get(timeout, unit); } 111 112 catch (ExecutionException e) 113 { throw new UncheckedExecutionException(e); } 114 115 catch (InterruptedException e) 116 { throw new UncheckedInterruptedException(e); } 117 118 catch (TimeoutException e) 119 { throw new UncheckedTimeoutException(e); } 120 121 catch (CompletionException e) 122 { 123 Throwable c = e.getCause(); 124 if (c == null) throw e; 125 if (c instanceof RDPException) throw (RDPException) c; 126 if (c instanceof BrowserException) throw (BrowserException) c; 127 if (c instanceof BrowserErrorException) throw (BrowserErrorException) c; 128 if (c instanceof AsynchronousException) throw (AsynchronousException) c; 129 throw e; 130 } 131 } 132}