Re: WebSocket client API

2015-09-01 Thread Roger Riggs

Hi Pavel,

A few comments on the API:

 - The Incoming class combines separate functions that would be easier to
   use if the methods were directly on the Builder.  It would also 
allow (not require)

   lambda's to be used or method references if the code was complex.
   The Builder methods can use generic java.util.function interfaces 
with the appropriate parameter types.
   Each of the callbacks should include the websocket, though with 
lambda it could capture
   the WS as needed.  For example,  (also separating close and error 
callbacks)


|WebSocket ws = WebSocket.newBuilder("ws://websocket.example.com") 
.onReceiveText( (ws, text) -> System.out.println(text)) .onError( (ws, 
t) -> t.printStackTrace()) .onClose( (ws, msg) -> 
System.out.println("closing: " + msg))  .create();|


 - The design to wrap the Outgoing data creates an extra step that 
makes the API
   a bit harder to use.  It would be more natural to add the sendAsync  
methods to WebSocket

   and avoid the creation of extra objects.

|ws.sendAsync("hello"); ws.sendAsync(bytebuffer); // an alternate 
signature could use varargs, ByteBuffer data... |



Roger

||

On 8/31/2015 10:30 AM, Pavel Rappo wrote:

Hi,

I would appreciate if you help to review a WebSocket client API proposed for
JDK 9. This work is a part of JEP-110 [1] and has started its public path with
HTTP client review in March this year [2].

Proposed WebSocket API is relatively small and focuses on convenient exchange of
data in a fully asynchronous fashion. API consists of 6 types located in the
java.net package [3]:

1. WebSocket
2. WebSocket.Builder
3. WebSocket.Incoming
4. WebSocket.Incoming.Chunks
5. WebSocket.Outgoing
6. WebSocketException

Starting point is a class description for java.net.WebSocket. Along with
in-javadoc examples, several API test samples are provided in the webrev [4] and
named test/java/net/WebSocket/Example%.java. They are only for informational
purposes and won't be included in the final version of the API.

I would appreciate any feedback on this API. Thanks.

---
[1] http://openjdk.java.net/jeps/110
[2] http://mail.openjdk.java.net/pipermail/net-dev/2015-March/008932.html
[3] http://cr.openjdk.java.net/~prappo/8087113/javadoc.00/
[4] http://cr.openjdk.java.net/~prappo/8087113/webrev.00/

-Pavel




Re: WebSocket client API

2015-09-01 Thread Pavel Rappo
Hi Joakim,

First of all, thank you so much for such a comprehensive list of questions! I'll
try to answer them to the best of my knowledge.

But before, I need to clarify one thing. I've noticed many of the questions are
about lack of some advanced features in the API. Well, they are for sure
negotiable, but let's for now (for initial pass) answer those as "[*]" (to not
repeat the same argument over and over again), which would mean the following:

  We have a design goal for this to be a very lightweight API. It focuses on
  simplicity and convenience of data exchange -- primary service provided by the
  WebSocket protocol. The feature mentioned seems to be an advanced one, and
  though might be very useful for other APIs, at first glance doesn't look like
  a necessary requirement from our point of view.

> On 31 Aug 2015, at 18:01, Joakim Erdfelt  wrote:
> 
> - There's 2 ways some of the websocket headers can be declared, and 1 way for 
> others.
>Origin   - easy enough, only in HttpClient.

This particular header may only be set by an HttpClient.

>Sec-WebSocket-Protocol   - easy enough to declare as header in HttpClient, 
> but it also exists in WebSocket.Builder (with a nice interface), but what 
> happens if both are used?

This is a good question. I think the expected behaviour would be to overwrite
headers specified in the HttpClient with those specified in the
WebSocket.Builder. This should be mentioned explicitly in the javadoc though.
Thanks.

It might be harder to overwrite 'Sec-WebSocket-Extensions' header, since its
values might be spread across several fields. But that's more of a concern from
an implementation point of view rather than from an API's.

Another option would be to throw some sort of unchecked exception. But I think
it's less robust and might not be a good choice here.

>Sec-WebSocket-Extensions - this is tricky to declare correctly, the 
> extensions themselves should be the canonical source for a properly formatted 
> Extension (with parameters) for this header.  
>   I think it's a mistake to rely on only String 
> here.
>   See the history of extension configuration 
> strings in the various PMCE specs.

Interesting. Could you please provide any links and/or examples? To be honest, I
suspect most users will simply copy-paste opaque strings with required
extensions' configurations for particular servers and since the syntax is
well-defined, there's nothing to worry about. But yes, I've noticed it's done
differently in other APIs.

There's one more reason that extensions have never been represented by anything
other than strings. As previously mentioned, since the intention is to keep this
API lightweight and as you can see no negotiation process abstraction is
provided, it's basically a single shot action. User states what they need
(subprotocol, extensions, etc.) Then user (hopefully) gets a connection. Then
user checks with accessors (extensions/subprotocol) what's in-use and if, for
some reason, they don't like the result, they simply abandon the WebSocket and
try again differently.

> - Make sure that adding Cookies to the upgrade is bullet-proof, its the 
> feature with the most questions on 
>  stackoverflow (for all languages, even the Javascript WebSocket API)

Thanks. I will keep an eye on that.

> - Errors during upgrade are communicated only via the WebSocket.create() and 
> WebSocket.createAsync() exceptions.
>  Access to the HTTP Response (headers, and status codes) are very important, 
> even when using the
>  non HttpClient version via WebSocket.newBuilder(String uri)

So if I understand you correctly you are saying that in case of a failed
negotiation, the Builder should throw an exception with HTTP response fields? Is
that for diagnostics or for some other reason?

> - Add new WebSocket.newBuilder(URI) method for formal URI use

OK. Btw, do you think that String version has a certain value or we are better
without it? In my opinion it looks nicer (shorter) in examples, and removes
additional boilerplate code. But I'm not too sure about real life usage.

> Extensions:
> 
> - Extensions should be better formalized, real objects, or at least real 
> configuration objects.
> - New extension implementations should be able to be provided.
> - WebSocket.extensions() should have apidoc indicating that it is list of 
> extensions that were negotiated during the upgrade.
> - How can someone plug in a new extension implementation?

Initially there were some thoughts on designing an SPI for extensions. But
having analyzed the history and the current state of official extensions these
ideas were set aside. I'm sure you know well that out of 2 official extensions
that hit the RFC road (mux [1], perframe-compress [2]) none succeeded. mux's
been abandoned because of similar features in HTTP/2; after consecutive 5
drafts, perframe-compress turned into PMCE [3] -- a spec for compression
exte