Package Torello.Java.Additional
Class Promise<RESPONSE,RESULT>
- java.lang.Object
-
- Torello.Java.Additional.Promise<RESPONSE,RESULT>
-
- Type Parameters:
RESPONSE
- This type is the 'Reponse Type' that is produced by the Asynchronous I/O. In the case of the WebSocket's Processor used by the Browser Remote Debugging Protocol, this type will always beJsonObject
.
The web-browser Remote Debugging Protocol solely uses JSON in those communications.RESULT
- This type indicates the type used by return-value that's ultimately received by the user. This type is the class which is actually returned when a user makes a call toPromise.await()
.
- All Implemented Interfaces:
java.io.Serializable
public class Promise<RESPONSE,RESULT> extends java.lang.Object implements java.io.Serializable
A promise keeps the processing logic for converting a response from an asychronous connection into a result that the end-user can utilize.
The three classes,Script
,Promise
andSender
are designed to allow for the creation of 'Asynchronous Scripts' that may be executed and made to appear to be synchronous through thePromise.await()
method.
These three classes are made use of in the Browser Remote Debugging Protocol Package. Theoretically, they could be used by any asynchronous communication system.- See Also:
- Serialized Form
Hi-Lited Source-Code:- View Here: Torello/Java/Additional/Promise.java
- Open New Browser-Tab: Torello/Java/Additional/Promise.java
File Size: 14,062 Bytes Line Count: 328 '\n' Characters Found
-
-
Field Summary
Serializable ID Modifier and Type Field protected static long
serialVersionUID
Asynchronous Response Processor Modifier and Type Field Function<RESPONSE,RESULT>
receiver
Debug Flag Modifier and Type Field static boolean
DEBUGGING
-
Method Summary
Retrieve this Promise' State Modifier and Type Method Ret5<Boolean,
Boolean,
RESULT,
Integer,
String>getState()
boolean
hadError()
boolean
hadResponse()
Report State to this Promise Modifier and Type Method void
acceptError(int errorCode, String errorMessage)
void
acceptResponse(RESPONSE response)
void
acceptThrowable(int errorCode, Throwable t)
Await for Script Completion to get Promise' Result Modifier and Type Method RESULT
await()
Register a Promise-Result Handler, to be invoked when Promise Completes Modifier and Type Method void
then(Consumer<RESULT> handler)
Retrieve this Promise' Result (for already completed Promise-Objects) Modifier and Type Method RESULT
result()
-
-
-
Field Detail
-
serialVersionUID
protected static final long serialVersionUID
This fulfils the SerialVersion UID requirement for all classes that implement Java'sinterface java.io.Serializable
. Using theSerializable
Implementation offered by java is very easy, and can make saving program state when debugging a lot easier. It can also be used in place of more complicated systems like "hibernate" to store data as well.- See Also:
- Constant Field Values
- Code:
- Exact Field Declaration Expression:
protected static final long serialVersionUID = 1;
-
DEBUGGING
public static boolean DEBUGGING
When assignedTRUE
, prints Diagnostic Information via- Code:
- Exact Field Declaration Expression:
public static boolean DEBUGGING = true;
-
receiver
public final java.util.function.Function<RESPONSE,RESULT> receiver
This is the "Respone Processor". As of the writing of this class, the only use that the three classes: Script, Promise & Sender has been for implementing the Google Chrome Browser Remote Debug Protocol. (Although perhaps these classes will one day be used with a different asychronous protocol) In this current case (Browser RDP), this receiver is actually doing the "JSON Binding" to bind the JsonObject received from the Browser into a Java Class that the user can actually use.- Code:
- Exact Field Declaration Expression:
public final Function<RESPONSE, RESULT> receiver;
-
-
Constructor Detail
-
Promise
public Promise(java.util.function.Function<RESPONSE,RESULT> receiver)
Constructing an instance ofPromise
only requires this response-processor (a.k.a. a 'receiver').- Parameters:
receiver
- This receiver needs to be able to convert the raw asynchronous response - which is just aJsonObject
when used by the Browser RDP Web-Socket Channel - into an instance of'RESULT'
that the end user can actually use.
-
-
Method Detail
-
hadError
public boolean hadError()
Asks'this'
instance ofPromise
whether or not an error has been reported.- Returns:
TRUE
if there were errors reported by the asynchronous channel, andFALSE
otherwise.- Code:
- Exact Method Body:
return this.error;
-
hadResponse
public boolean hadResponse()
Asks'this'
instance ofPromise
whether any response has been reported. This shall returnTRUE
if either an error, or a response has been received.- Returns:
TRUE
if a response or an error has been reported to'this'
instance, andFALSE
otherwise.- Code:
- Exact Method Body:
return this.response || this.error;
-
getState
public Ret5<java.lang.Boolean,java.lang.Boolean,RESULT,java.lang.Integer,java.lang.String> getState ()
Gets all current-state of thisPromise
- Returns:
- The current state of this
Promise
, as an instance ofRet5
.-
Ret5.a (Boolean)
:
Whether or not a response has been reported
-
Ret5.b (Boolean)
:
Whether or not an error has been reported
-
Ret5.c (RESULT)
:
The result that has been returned, or null if no result has been received
-
Ret5.d (Integer)
:
The error-code that was received, or 0 if no errors have been reported
-
Ret5.e (String)
:
The error-message (if an error was reported), or null.
-
- Code:
- Exact Method Body:
return new Ret5<>(this.response, this.error, this.result, this.errorCode, this.errorMessage);
-
result
public RESULT result()
This allows a user to retrieve the result of'this'
asynchronousPromise
. Note that if no result has been received yet, this method throws an exception.- Returns:
- The result of the asynchronous call.
- Throws:
AynchronousException
- This throws if thisPromise
has not received a result yet.- Code:
- Exact Method Body:
if (! this.response) throw new AsynchronousException("No response has been received yet"); return this.result;
-
acceptResponse
public final void acceptResponse(RESPONSE response)
When building a communication-system that uses theseScript & Promise
classes, that system needs to invoke'acceptResponse'
whenever a server-response has been received.
With aWebSocket
connection to a Web-Browser via the Remote Debugging Port, mapping the response & request is done by checking the request-ID, and keeping a mapping of ID => "un-answered Promise Objects."- Parameters:
response
- The response received from the communications channel, Web-Socket, browser etc...- Code:
- Exact Method Body:
if (DEBUGGING) System.out.println( "Promise.acceptResponse(RESPONSE response) invoked\n" + "response=" + StrPrint.abbrev(response.toString(), true, true, null, 80) ); if (this.error) throw new AsynchronousException( "This Promise cannot accept a response object because it has already received " + "an error. Current Error Code: [" + this.errorCode + "]" + ((this.errorMessage != null) ? ("\nCurrent Error Message: \"" + this.errorMessage + "\"") : "") ); if (this.response) throw new AsynchronousException ("This Promise has already received a response. A second response is not allowed."); this.result = this.receiver.apply(response); this.response = true; // ✅ COMPLETE the future with the result this.future.complete(this.result);
-
acceptError
public final void acceptError(int errorCode, java.lang.String errorMessage)
If an error occurs in communications-channel logic, that error may be reported to thisPromise
by calling'acceptError'
.- Parameters:
errorCode
- A meaningful error-code.errorMessage
- A meaningful error-message- Throws:
AsynchronousException
- If'this'
instance of'Promise'
has already received an error (via'acceptError'
), or if'this'
has accepted a response (viaacceptResponse(Object)
).- Code:
- Exact Method Body:
if (DEBUGGING) System.out.println( "Promise.acceptThrowable(int errorcode, String errorMessage) invoked\n" + "errorCode=" + errorCode + ", errorMessage=[" + errorMessage + ']' ); if (this.error) throw new AsynchronousException( "There has already been an error reported to this Promise. Current Error Code: [" + this.errorCode + "]" + ((errorMessage != null) ? ("\nError Message: \"" + errorMessage + "\"") : "") ); if (this.response) throw new AsynchronousException ("This Promise has already received a response. It is too late to report an error."); this.error = true; this.errorCode = errorCode; this.errorMessage = errorMessage; this.future.completeExceptionally( new AsynchronousException ("Received async error: code=" + errorCode + ", msg=" + errorMessage) );
-
acceptThrowable
public final void acceptThrowable(int errorCode, java.lang.Throwable t)
Reports an asynchronous failure to thisPromise
by attaching aThrowable
instance and an error code. This method allows the caller to propagate a real exception (such as anIOException
,NullPointerException
, etc.) as the cause of asynchronous failure, while still assigning a numeric error code for internal tracking.
This method may only be called once perPromise
. If thisPromise
has already received a result (viaacceptResponse(Object)
), or if it has already received an error (viaacceptError(int, String)
or another call toacceptThrowable
), anAsynchronousException
will be thrown.
Internally, this method completes the underlyingCompletableFuture
by callingcompleteExceptionally(...)
with a newAsynchronousException
, which wraps the originalThrowable
as part of the message and the cause chain.- Parameters:
errorCode
- A numeric error code, used to distinguish between different error types or failure scenarios. This value will be accessible viagetState()
.t
- TheThrowable
instance that triggered or represents this asynchronous failure. Its message will be used as theerrorMessage
for thisPromise
, and the throwable itself will be wrapped into anAsynchronousException
.- Throws:
AsynchronousException
- If thisPromise
has already been completed, either by a response or an earlier error.- Code:
- Exact Method Body:
if (DEBUGGING) System.out.println( "Promise.acceptThrowable(int errorCode, Throwable t) invoked:\n" + "errorCode=" + errorCode + ", " + "Throwable.class=" + t.getClass().getSimpleName() + ", " + "Throwable.message=[" + t.getMessage() + ']' ); if (this.error) throw new AsynchronousException( "There has already been an error reported to this Promise. Current Error Code: [" + this.errorCode + "]" + ((this.errorMessage != null) ? ("\nError Message: \"" + this.errorMessage + "\"") : "") ); if (this.response) throw new AsynchronousException ("This Promise has already received a response. It is too late to report an error."); this.error = true; this.errorCode = errorCode; final String msg = t.getMessage(); this.errorMessage = "Throwable [" + t.getClass().getSimpleName() + "] " + ((msg != null) ? ("Message: " + msg) : "was Thrown."); this.future.completeExceptionally( new AsynchronousException( "Promise Completed with Throw\n" + "Please review Throwable Cause-Chain for Details.\n" + "Error Message: \"" + this.errorMessage + "\"\n" + "Error Code: [" + errorCode + "]\n" + t ));
-
await
public RESULT await()
This method will cede the currentThread's
control until the Asynchronous Channel has called this class'acceptResponse(Object)
method.- Returns:
- Once
'this'
instance of'Promise'
has been notified of a result, it will return that result, as an instance of Type-Parameter'RESULT'
. - Throws:
AsynchronousException
- If ajava.lang.InterruptedException
is thrown while awating thisPromise
, that exception will be wrapped into an instance of'AsynchronousException'
, and then thrown. This wrapper-exception is an un-checked,RuntimeException
.- Code:
- Exact Method Body:
try { return this.future.get(); } catch (InterruptedException e) { throw new AsynchronousException( "While awaiting this Promise, an InterruptedException was thrown.\n" + "See Exception getCause() for details.", e ); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) throw (RuntimeException) cause; if (cause instanceof Error) throw (Error) cause; // throw new AsynchronousException("ExecutionException occurred", e); throw new AsynchronousException( "While awaiting this Promise, an ExecutionException was thrown.\n" + "See Exception getCause() for details.", e ); }
-
then
public void then(java.util.function.Consumer<RESULT> handler)
Registers a callback to be executed asynchronously after thisPromise
receives its result. This method allows for chaining asynchronous logic without blocking the current thread.
This callback is passed the result of thisPromise
once the correspondingacceptResponse(Object)
method has been called, and thereceiver
has produced a validRESULT
object.
Unlikeawait()
, this method returns immediately and does not block the current thread.
Example usage:
Target.createTarget(...).exec(browserSender).then(MyClass::handleCreatedTarget);
- Parameters:
handler
- AConsumer
that will be invoked asynchronously with the result of thisPromise
when it becomes available.- Code:
- Exact Method Body:
this.future.thenAccept(handler);
-
-