jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: [JAVASERVERFACES-SPEC_PUBLIC-1396] f:socket for SSE and WebSocket PROPOSAL

From: Edward Burns <edward.burns_at_oracle.com>
Date: Fri, 18 Dec 2015 10:02:17 -0800

Thanks for this work and sorry for my inactivity.

>>>>> On Mon, 7 Dec 2015 10:23:22 +0100, Bauke Scholtz <balusc_at_gmail.com> said:

B> Hi,
B> Last weekend I developed and added o:socket for OmniFaces, which could be
B> used as base for f:socket:
B> http://omnifaces.org/docs/javadoc/current/org/omnifaces/cdi/push/Socket.html
B> Source code can be found here:
B> https://github.com/omnifaces/omnifaces/tree/master/src/main/java/org/omnifaces/cdi/push
B> (4 classes).

B> Some considerations I took are however differ from f:socket:

B> - I dropped SSE support. As per http://caniuse.com/#feat=websockets vs
B> http://caniuse.com/#feat=eventsource the WS enjoy broader support
B> (IE/Edge!) and the protocol is also much more efficient than SSE (no
B> persistent open connection). A single protocol also keeps server/client
B> side code much simpler.

For f:socket, I agree to only support websocket. In that case, I
suggest we rename it to f:websocket. This lets us drop the "transport"
attribute also.

B> - I dropped proposed widgetvar/autoconnect attributes and instead added
B> enabled attribute. It basically controls whether the underlying WS init
B> script will be rendered or not.

This much sounds good.

B> This is evaluated during view render time and can be
B> ajax-updated.

What can be ajax-updated, the value of the "enabled" attribute? If
that's the case, there must be a server side UIComponent corresponding
to f:websocket. Is that the case in your design?

B> The socket can be explicitly closed via a public script function
B> taking just channel name.

Now we're getting into JS API defining territory. How about we make it
so when you open a WebSocket with <f:websocket id="foo"> we populate a
JavaScript associative array named "jsf.websocket" such that

jsf.websockets["foo"]

you get the actual JavaScript WebSocket object? This will have its
onopen, onerror, onmessage, onclose function references set as described
in the tag attributes.
       
B> - I dropped proposed onerror attribute and instead added onclose attribute.
B> It will also be invoked during onerror and is more useful as the CloseEvent
B> is then available which also contains the error code. The script is written
B> that way that it's also invoked when WS is not supported (e.g. IE6-9), a
B> custom error code of -1 is then passed.

How can you get away with dropping onerror when it's part of the W3C
WebSocket API? [1]

B> The combination with o:commandScript (similar component is also scheduled
B> for JSF 2.3, see spec issue 613) makes it a very nice tool to trigger ajax
B> updates via push.

OK, we'll take that up over there.

>>>>> On Mon, 7 Dec 2015 19:08:52 +0100, arjan tijms <arjan.tijms_at_gmail.com> said:

AT> Would be great if a version of this can be pushed to the RI before long.
AT> It's been a while since the last commit for a 2.3 feature, and nothing
AT> better to keep the community interested than some actual working code they
AT> can play around with I guess ;)

>>>>> On Mon, 7 Dec 2015 20:56:02 +0100, Michael Müller <michael.mueller_at_mueller-bruehl.de> said:

MM> Looks great for pushing data from server to client.
MM> But how to send data from client to server?
MM> Do we need something like
MM> public void receiveMessage?
MM> Or shall standard socket handling be used?

Rather than Ajax, I think it's more natural to just allow the developer to
get access to the actual WebSocket, as I proposed above.

>>>>> On Tue, 8 Dec 2015 20:38:10 +0100, Bauke Scholtz <balusc_at_gmail.com> said:

B> It would only require a change in PartialViewContext API. It must offer a
B> method which triggers the partial response writer to start and end the
B> <eval>. Right now this is nowhere available in public API and even not in
B> Mojarra implementation. Directly accessing the PartialResponseWriter to
B> achieve the <eval> job isn't possible. I'd propose adding
B> PartialViewContext#getEvalScripts() which returns a mutable List<String> so
B> that the developer can add scripts to <eval> of the <partial-response>.
B> This allows easily executing scripts on complete of ajax response. Both
B> OmniFaces and PrimeFaces have an enhanced PartialViewContext implementation
B> which offers this additional method which is ultimately used by
B> respectively RequestContext#execute() and Ajax#oncomplete(). The <o:socket>
B> uses it to open/close the push channel during ajax requests depending on
B> its "enabled" attribute.

Yes, I like this proposal. Can you please file a separate JIRA for that
and open up a discussion thread here citing it?

B> Further the o:socket encodes the push message as JSON string in and the
B> receiver script parses it back to JSON object before invoking the onmessage
B> function. This JSON step is not necessary, but really nice to have. Only,
B> it may require an internal JSON encoder or perhaps the javax.json API
B> (which is unfortunately not available on servletcontainers like Tomcat and
B> Jetty on contrary to WebSockets). I could omit the JSON feature and leave
B> it up to the developer. If JSON is not mandatory, it will be easy to create
B> an API and impl for the RI.

I have no problem depending on javax.json. We are an EE spec after all.

>>>>> On Tue, 8 Dec 2015 23:09:45 +0100, arjan tijms <arjan.tijms_at_gmail.com> said:

AT> If I understood correctly, JSF 2.3 can depend on pretty much everything
AT> from the Java EE Web Profile, so this shouldn't be a problem by itself. For
AT> Tomcat and friends it would then be a matter of adding the JSON encoder
AT> separately, wouldn't it? That's currently how it works for the CDI and
AT> BeanValidation dependencies.

We can fully depend on EE8. That even means Servlet 4.0. This is a
departure from all preceding revisions of JSF.

AT> Nevertheless, may be nice to see if some explicit pluggability mechanism
AT> can be used here.

No thank you. We have enough pluggability already.

AT> For an initial version in Mojarra it may be an option to omit JSON first,
AT> and then do the JSON support in a second iteration.

I disagree, let's keep it in.

B> I only wonder if both you and Ed agree on taking over the <o:socket> in its
B> current form for JSF 2.3 <f:socket>. Among others, I omitted the SSE
B> support as it isn't standardized yet while WS is even backed by a Java EE
B> API (JSR356) which is even implemented in barebones servletcontainers like
B> Tomcat and Jetty. And, some attributes have been reworked to keep it as
B> simple as possible.

I'd like to get an answer to my question about whether or not there is a
server side UIComponent for each <f:websocket>. If so, we may have some
more fundamental architectural differences of opinion.

>>>>> On Thu, 10 Dec 2015 14:49:31 +0100, Bauke Scholtz <balusc_at_gmail.com> said:

B> Yes, interpret it as ".. agree on me taking over .." :) Currently still
B> work in progress, programmatic CDI management is not funny.

See preceding question.

B> Just in case, I made some more changes to OmniFaces socket:
B> - Added "port" attribute which allows explicitly specifying WS server port
B> number (as it's possible that the very same container runs the WS server on
B> a different port than the HTTP server).
B> - Endpoint is now lazily programmatically registered on first usage of
B> o:socket instead than eagerly on startup.
B> - Endpoint now accepts only connections from predefined channel names (the
B> ones specified in o:socket channel attribute), all others will just be
B> aborted by an exception.

These are fine.

>>>>> On Fri, 11 Dec 2015 12:50:35 +0000, Bauke Scholtz <balusc_at_gmail.com> said:

B> It has in the meanwhile been further improved though. For a live demo, see
B> also http://snapshot.omnifaces.org/push/socket

This is a lot of momentum!

>>>>> On Wed, 16 Dec 2015 20:55:37 +0100, Bauke Scholtz <balusc_at_gmail.com> said:

B> While developing and testing the o:socket I wasn't satisfied with how WS
B> session and HTTP session interacted with each other (among others, HTTP
B> session timeout doesn't trigger a re-handshake of the WS session, causing
B> its endpoint config to still refer the old HTTP session), so I have further
B> improved the o:socket to be less dependent on that and made even more
B> Portlet friendly as there are no hard javax.servlet dependencies
B> anymore.

Yes, those two session objects are entirely disjoint, and necessarily
so. To access the HttpSession from the WebSocket session, you must save
it aside during the handshake. Perhaps we can make that easier so you
can have access to it automatically?

B> For security, there's currently in o:socket only a servlet filter in place
B> which should return 400 on WS handshake requests on non-existing channels:
B> https://github.com/omnifaces/omnifaces/blob/master/src/main/java/org/omnifaces/cdi/push/SocketChannelFilter.java.

B> As this isn't Portlet compatible, I'm for Mojarra's f:socket thinking to
B> programmatically add /javax.faces.push/* to servlet mapping and then do the
B> job in FacesServlet instead. Would this be OK for Portlets too? Neil? Or
B> perhaps I should append the current FacesServlet mapping to the push URL
B> and then inspect the presence of the /javax.faces.push prefix as currently
B> also done for /javax.faces.resource requests.

This is my biggest beef with p:socket. It's a pain to set up. I'd
really like to make it so you don't have to do any additional set up.
We can bake this functionality straight into the FacesServlet.

Can you rework your impl to do it that way?

Ed

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
[1] http://www.w3.org/TR/2011/WD-websockets-20110419/#the-websocket-interface