jsr356-experts@websocket-spec.java.net

[jsr356-experts] Re: Summarizing discussion about requirements

From: Greg Wilkins <gregw_at_intalio.com>
Date: Wed, 25 Apr 2012 11:08:50 +1000

On 25 April 2012 09:53, Danny Coward <danny.coward_at_oracle.com> wrote:

> Hi folks,
>
> Thanks for all your comments and suggestions. One thing that has worked
> well in groups I've been involved with in the past is for me to summarize
> every so often the most recent discussions. It's helpful to me as a way of
> making sure I have read everything, and also to expert members that
> sometimes don't have time to read every email but who need to be able to
> jump back into the discussion when they do have time.
>
Here's a first summary of the discussion arising from the requirements
> document I sent around, your comments welcome, of course.
>


OK, but do you want comments on these summaries to be in the same thread
or broken back out into subject related threads or back on the original
thread? I'll comment here for now.



>
> Relationship with Servlet 3.1
>
> Perhaps the requirement I sent out was confusingly stated as it raised
> variety of issues ! Perhaps this will help:
>
> - Servlet version: We'd (speaking for our team at Oracle) certainly like
> to be able to deliver our implementation of the WebSocket API that can run
> on servlet 3.1 since it is intentionally designing a nice HTTP Upgrade
> handoff api and perhaps a new async I/O. So, intention of the requirement
> was a flag not to put something in the WebSocket API to prevent that
> situation being possible. Now, if others here want to build an
> implementation that runs on earlier servlet versions, I think that would be
> goodness too, in which case we should beware of adding things in the spec
> that would preclude someone building this API on a servlet 2.5 container
> too.
>
> - Does anyone plan on building an implementation of this on a pre-servlet
> 3.1 container ? If so, which version ?
>

Jetty will definitely support this in our 2.5 servlet container. As soon
as we have a rough draft we will probably support that in jetty to get some
feedback. I'd much rather our users worked with a rough draft than with
our own API.



> - API dependency: It was the not intention that this requirement imply
> that the JSR356 APIs would explicitly depend on the servlet API. (Although
> I do agree with Justin that exposing the HttpSession probably would be
> useful, in the situation that the WebSocket API is running in the servlet
> container.)
>

We also have users wanting access to cookies (for their own auth) as well
as remote and local IP address/port. With session access, we need to note
that a session lifecycle may be shorter than a websocket connection and
that it may timeout and be invalidated while the websocket connection is
still in use. Perhaps there is a need for a mechanism to keep the session
alive, but my preference is to keep them separate. Best to make the
session available during the connection, but then any long term state would
need to be kept in a websocket session with a different lifecycle to the
Http session?

As the initial request is a HTTP upgrade request, it is tempting to allow
the application to accept/deny the connection using normal servlet
mechanisms - although it is currently unlikely that browsers will react
correctly to a 401 auth challenge from a security constraint. Also not
that when websocket MUX is introduced, the connections will have the same
semantics as a HTTP upgrade request, but will not actually be a HTTP
request. So I tend to think that we will need to abstract all the useful
data (IP,port,cookies,sessions) away from the Request object.


- Co-packaging the Web Socket API implementation with EARs/WARs:
>
> I'd certainly not envisioned it like that: I'd expected, as I think Greg
> and Remy both outlined, that people wanting to support JSR356 in EE would
> extend the container, with nothing but annotated POJOs in the WAR/EAR.
> Rather than require co-packaging the implementation as a library with
> applications. But I think it would be ok if people want to deliver the
> implementation that way.
>

I agree that we need to support both modes, plus I think this also extends
to extensions. Obviously a co-packaged impl would be able to provide its
own extensions for compression, MUX etc. Likewise and in container impl
should be able to provide its own common extensions. I'm not so sure
about mixed modes... do we want to support a container websocket
implementation with application extensions? If so, then we need a
standard extension API as well... which could be hard. So perhaps an
extension API is something for 2.0 and for now only extensions supported by
the actual impl will be available.




>
> Client APIs
>
> So, we have a few strong votes to make sure we deliver a client API in the
> first version. Good to know ! As someone pointed out, most of the API is
> symmetrical, save for the handshake. Unless someone has a good reason to
> support earlier versions of the JDK, I'd suggest we take a baseline of JDK
> 7 i.e. the client api works on JDK7 and anything above. Does that sound
> reasonable ?
>

I'm OK with JDK7.

I'm interested to know if we are thinking about JDK-7 NIO.2 style for the
API - ie using futures and/or completion handlers.



> Content Encoding
>
> It seems clear that developers will want to encode/decode messages. I'd
> envisioned something relatively simple, along the lines that Scott sketched
> out, or such as can be found in JAX-RS. But I'm also sympathetic to
> Justin's point about adding another similar-but-different api for content
> encoding/decoding for EE developers. And yet leaving developers with just
> Strings and byte[] arrays doesn't seem right either. I'd like to hear what
> others think about this.
>

The problem with allowing the implementation to do the encoding of objects
to bytes is that it greatly complicates the semantics. Will the API be
pass by reference or pass by value? ie if you change an objects value after
you call the send API, but before it is actually sent, does that change
get reflected in the bytes sent? I think pass by reference can be
confusing and dangerous, so I prefer pass by value - which implies that
serialisation is performed as soon as the send API is called - in which
case it can be easily done in a wrapper of the API.

Websockets provides the semantics of sending Strings and byte[] as discrete
messages - I think we should first focus on supporting that and then see if
there is an appropriate space to support Object as well or if that can be
punted to an API wrapper.



Message Queuing
>
> I hadn't thought about requiring yet much in this area, except to say that
> I agree with Scott's point about basic quality of service like: sending a
> message to a bad peer should not hang the current thread. Does anyone have
> any other message-queue related thoughts ?
>

MUX is coming and has explicit flow control and we already have TCP/IP flow
control with normal websockets. So a hard requirement that I see is
that a slow consumer MUST stop a fast producer. The producer can be
stopped either with blocking sends or with some async API (callback
handlers, futures etc.), but we can't have an infinite internal queue that
can grow forever.

I think most users will be happy with a simple blocking API, but I also
think an async send will be required for scalable applications built on
this. So we could provide both a blocking and async API, but I would note
that the NIO.2 Future style can provide blocking from within an Async API
pretty simply.

   Future<Boolean> sent = websocket.send(mymessage);
   if (!sent.get())
       throw new IOException("my message was not sent");

But that still leaves open the question of can another send be done before
the future of the previous send is complete? NIO.2 style would say that
you can only have one outstanding send, so message queuing is done in the
applications. However the definition of the future being complete does not
mean that the message has actually been sent, and it could just mean that
the message has been framed and copied into an output buffer and that the
passed mymessage buffer can now be changed. If this is the interpretation
we go with, then an app can still do

   websocket.send(mymessage0).get();
   websocket.send(mymessage1).get();
   websocket.send(mymessage2).get();
   websocket.send(mymessage3).get();

to send multiple messages in quick succession and not block... unless the
internal buffer actually fills.