105 private final Receiver receiver; |
105 private final Receiver receiver; |
106 private final SequentialScheduler receiveScheduler = new SequentialScheduler(new ReceiveTask()); |
106 private final SequentialScheduler receiveScheduler = new SequentialScheduler(new ReceiveTask()); |
107 |
107 |
108 public static CompletableFuture<WebSocket> newInstanceAsync(BuilderImpl b) { |
108 public static CompletableFuture<WebSocket> newInstanceAsync(BuilderImpl b) { |
109 Function<Result, WebSocket> newWebSocket = r -> { |
109 Function<Result, WebSocket> newWebSocket = r -> { |
110 WebSocketImpl ws = new WebSocketImpl(b.getUri(), |
110 WebSocket ws = newInstance(b.getUri(), |
111 r.subprotocol, |
111 r.subprotocol, |
112 b.getListener(), |
112 b.getListener(), |
113 r.transport); |
113 r.transport); |
114 // This initialisation is outside of the constructor for the sake of |
114 // Make sure we don't release the builder until this lambda |
115 // safe publication of WebSocketImpl.this |
|
116 ws.signalOpen(); |
|
117 // make sure we don't release the builder until this lambda |
|
118 // has been executed. The builder has a strong reference to |
115 // has been executed. The builder has a strong reference to |
119 // the HttpClientFacade, and we want to keep that live until |
116 // the HttpClientFacade, and we want to keep that live until |
120 // after the raw channel is created and passed to WebSocketImpl. |
117 // after the raw channel is created and passed to WebSocketImpl. |
121 Reference.reachabilityFence(b); |
118 Reference.reachabilityFence(b); |
122 return ws; |
119 return ws; |
128 return failedFuture(e); |
125 return failedFuture(e); |
129 } |
126 } |
130 return h.send().thenApply(newWebSocket); |
127 return h.send().thenApply(newWebSocket); |
131 } |
128 } |
132 |
129 |
133 WebSocketImpl(URI uri, |
130 /* Exposed for testing purposes */ |
134 String subprotocol, |
131 static WebSocket newInstance(URI uri, |
135 Listener listener, |
132 String subprotocol, |
136 TransportSupplier transport) |
133 Listener listener, |
|
134 TransportSupplier transport) { |
|
135 WebSocketImpl ws = new WebSocketImpl(uri, subprotocol, listener, transport); |
|
136 // This initialisation is outside of the constructor for the sake of |
|
137 // safe publication of WebSocketImpl.this |
|
138 ws.signalOpen(); |
|
139 return ws; |
|
140 } |
|
141 |
|
142 private WebSocketImpl(URI uri, |
|
143 String subprotocol, |
|
144 Listener listener, |
|
145 TransportSupplier transport) |
137 { |
146 { |
138 this.uri = requireNonNull(uri); |
147 this.uri = requireNonNull(uri); |
139 this.subprotocol = requireNonNull(subprotocol); |
148 this.subprotocol = requireNonNull(subprotocol); |
140 this.listener = requireNonNull(listener); |
149 this.listener = requireNonNull(listener); |
141 this.transmitter = transport.transmitter(); |
150 this.transmitter = transport.transmitter(); |
360 // signal, but apparently nothing has changed |
369 // signal, but apparently nothing has changed |
361 break; |
370 break; |
362 default: |
371 default: |
363 throw new InternalError(String.valueOf(s)); |
372 throw new InternalError(String.valueOf(s)); |
364 } |
373 } |
365 // Do not keep references to arbitrary big objects we no longer |
|
366 // need. It is unknown when the next message might come (if |
|
367 // ever), so the following references should be null the sooner |
|
368 // the better: |
|
369 binaryData = null; |
|
370 text = null; |
|
371 } catch (Throwable t) { |
374 } catch (Throwable t) { |
372 signalError(t); |
375 signalError(t); |
373 } |
376 } |
374 } |
377 } |
375 |
378 |