src/java.net.http/share/classes/jdk/internal/net/http/websocket/Transport.java
branchhttp-client-branch
changeset 56263 4933a477d628
parent 56092 fd85b2bf2b0d
child 56269 234813fd33bc
equal deleted inserted replaced
56262:d818a6a8295a 56263:4933a477d628
    26 package jdk.internal.net.http.websocket;
    26 package jdk.internal.net.http.websocket;
    27 
    27 
    28 import java.io.IOException;
    28 import java.io.IOException;
    29 import java.nio.ByteBuffer;
    29 import java.nio.ByteBuffer;
    30 import java.util.concurrent.CompletableFuture;
    30 import java.util.concurrent.CompletableFuture;
       
    31 import java.util.function.BiConsumer;
    31 
    32 
    32 /*
    33 /*
    33  * Transport needs some way to asynchronously notify the send operation has been
    34  * A WebSocket view of the underlying communication channel. This view provides
    34  * completed. It can have several different designs each of which has its own
    35  * an asynchronous exchange of WebSocket messages rather than asynchronous
    35  * pros and cons:
    36  * exchange of bytes.
    36  *
    37  *
    37  *     (1) void sendMessage(..., Callback)
    38  * Methods sendText, sendBinary, sendPing, sendPong and sendClose initiate a
    38  *     (2) CompletableFuture<T> sendMessage(...)
    39  * corresponding operation and return a CompletableFuture (CF) which will
    39  *     (3) CompletableFuture<T> sendMessage(..., Callback)
    40  * complete once the operation has completed (succeeded or failed).
    40  *     (4) boolean sendMessage(..., Callback) throws IOException
       
    41  *     ...
       
    42  *
    41  *
    43  * If Transport's users use CFs, (1) forces these users to create CFs and pass
    42  * These methods are designed such that their clients may take an advantage on
    44  * them to the callback. If any additional (dependant) action needs to be
    43  * possible implementation optimizations. Namely, these methods:
    45  * attached to the returned CF, this means an extra object (CF) must be created
       
    46  * in (2). (3) and (4) solves both issues, however (4) does not abstract out
       
    47  * when exactly the operation has been performed. So the handling code needs to
       
    48  * be repeated twice. And that leads to 2 different code paths (more bugs).
       
    49  * Unless designed for this, the user should not assume any specific order of
       
    50  * completion in (3) (e.g. callback first and then the returned CF).
       
    51  *
    44  *
    52  * The only parametrization of Transport<T> used is Transport<WebSocket>. The
    45  * 1. May return null which is considered the same as a CF completed normally
    53  * type parameter T was introduced solely to avoid circular dependency between
    46  * 2. Accept an arbitrary attachment to complete a CF with
    54  * Transport and WebSocket. After all, instances of T are used solely to
    47  * 3. Accept an action to take once the operation has completed
    55  * complete CompletableFutures. Transport doesn't care about the exact type of
       
    56  * T.
       
    57  *
    48  *
    58  * This way the Transport is fully in charge of creating CompletableFutures.
    49  * All of the above allows not to create unnecessary instances of CF.
    59  * On the one hand, Transport may use it to cache/reuse CompletableFutures. On
    50  * For example, if a message has been sent straight away, there's no need to
    60  * the other hand, the class that uses Transport, may benefit by not converting
    51  * create a CF (given the parties agree on the meaning of null and are prepared
    61  * from CompletableFuture<K> returned from Transport, to CompletableFuture<V>
    52  * to handle it).
    62  * needed by the said class.
    53  * If the result of a returned CF is useless to the client, they may specify the
       
    54  * exact instance (attachment) they want the CF to complete with. Thus, no need
       
    55  * to create transforming stages (e.g. thenApply(useless -> myResult)).
       
    56  * If there is the same action that needs to be done each time the CF completes,
       
    57  * the client may pass it directly to the method instead of creating a dependant
       
    58  * stage (e.g. whenComplete(action)).
    63  */
    59  */
    64 public interface Transport<T> {
    60 public interface Transport {
    65 
    61 
    66     CompletableFuture<T> sendText(CharSequence message, boolean isLast);
    62     <T> CompletableFuture<T> sendText(CharSequence message,
       
    63                                       boolean isLast,
       
    64                                       T attachment,
       
    65                                       BiConsumer<? super T, ? super Throwable> action);
    67 
    66 
    68     CompletableFuture<T> sendBinary(ByteBuffer message, boolean isLast);
    67     <T> CompletableFuture<T> sendBinary(ByteBuffer message,
       
    68                                         boolean isLast,
       
    69                                         T attachment,
       
    70                                         BiConsumer<? super T, ? super Throwable> action);
    69 
    71 
    70     CompletableFuture<T> sendPing(ByteBuffer message);
    72     <T> CompletableFuture<T> sendPing(ByteBuffer message,
       
    73                                       T attachment,
       
    74                                       BiConsumer<? super T, ? super Throwable> action);
    71 
    75 
    72     CompletableFuture<T> sendPong(ByteBuffer message);
    76     <T> CompletableFuture<T> sendPong(ByteBuffer message,
       
    77                                       T attachment,
       
    78                                       BiConsumer<? super T, ? super Throwable> action);
    73 
    79 
    74     CompletableFuture<T> sendClose(int statusCode, String reason);
    80     <T> CompletableFuture<T> sendClose(int statusCode,
       
    81                                        String reason,
       
    82                                        T attachment,
       
    83                                        BiConsumer<? super T, ? super Throwable> action);
    75 
    84 
    76     void request(long n);
    85     void request(long n);
    77 
    86 
    78     /*
    87     /*
    79      * Why is this method needed? Since Receiver operates through callbacks
    88      * Why is this method needed? Since receiving of messages operates through
    80      * this method allows to abstract out what constitutes as a message being
    89      * callbacks this method allows to abstract out what constitutes as a
    81      * received (i.e. to decide outside this type when exactly one should
    90      * message being received (i.e. to decide outside this type when exactly one
    82      * decrement the demand).
    91      * should decrement the demand).
    83      */
    92      */
    84     void acknowledgeReception();
    93     void acknowledgeReception(); // TODO: hide
    85 
    94 
    86     void closeOutput() throws IOException;
    95     void closeOutput() throws IOException;
    87 
    96 
    88     void closeInput() throws IOException;
    97     void closeInput() throws IOException;
    89 }
    98 }