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

[jsr372-experts] Re: [jsr372-experts mirror] Re: websocket.

From: Bauke Scholtz <balusc_at_gmail.com>
Date: Wed, 11 Jan 2017 09:36:37 +0100

Hi Leo,

Thank you for the pointer to "h:scriptWebsocket". This is certainly not the
intent. It was somehow autogenerated during JSP targeted TLD generation
(not by VDL one!).

I will rectify this. Please ignore JSP docs and pay attention to VDL docs.

At least it has been changed from TagHandler to UIComponent (in order to
support <f:ajax>) with component family javax.faces.Script and component
type javax.faces.Websocket.

Cheers, B


On Wed, Jan 11, 2017, 03:05 Leonardo Uribe <leonardo.uribe_at_irian.at> wrote:

> Hi
>
>
> MM>> Technically, a websocket is an upgrade of the HTTP protocol which
> MM>> establishes a bidirectional communication channel between two peers.
> Once
> MM>> the connection is established it will be kept open until one of the
> peers
> MM>> closes it. Thus, it can be used to send any time any information
> (with
> MM>> respect to technical limitations) from any of both peers to the
> other.
> MM>> Because the channel is open all the time, this connection is faster
> MM>> than a series of HTTP request response cycles.
>
> MM>> Although a websocket establishes a channel between two peers, it is
> MM>> broadly used to broadcast information from one server to all clients.
> MM>> An example might be a chat room, where all individual user inputs are
> MM>> distributed to all (other) users. A simplified version of this
> scenario
> MM>> might be implemented using Java EE 7 like this:
>
> @OnMessage
> public void onMessage(String message, Session session) throws
> IOException, EncodeException{
> for (Session peer : peers) {
> peer.getBasicRemote().sendObject(session.getId() + ": " +
> message);
> }
> }
>
> MM>> Within JSF, we may send data from client to server at any time by
> initiating
> MM>> an ajax request.
> MM>> But, before JSF 2.3 there is no standard way to push information from
> MM>> server to client.
>
> Yes, agreed.
>
> MM>> Here <f:websocket> comes into play.
> MM>> Via @Push the developer may push information from server to client.
> MM>> If I understood it correctly, a send(message) will perform a
> broadcast, whilst
> MM>> .send(message, user) will send to a named user.
>
> The name of the component seems to be changed at some point. According to
> the latest
> javadoc there is h:scriptWebsocket (but f:websocket still appears), so I
> guess
> that's the final name.
>
> h:scriptWebsocket has two attributes to control that broadcast: "scope"
> and "user".
> The javadoc says "... All open websockets on the same channel and user
> will
> receive the same push message from the server. ...".
>
> So, according to the "scope" attribute set for the channel, send(message)
> will
> perform the broadcast of that message. If "user" is set, the default scope
> is "session", not "application".
>
> MM>> What happens, if a couple of clients use the same value for user?
>
> Depends of the "scope" used to initialize the channel in
> h:scriptWebsocket. If the
> scope is "application" everyone sharing the same user token will receive
> the message.
> If the scope is "session", only the one sharing the same user and session
> will receive
> the message.
>
> MM>> Will it be a selective broadcast, e.g. like sending data to one of a
> couple
> MM>> of chatrooms?
>
> If you need an special logic, the idea is onOpen provides a point to
> initialize
> the channel and provide the custom logic. For a chatroom, set "user" and
> specify
> scope as "session" is the best option.
>
> MM>> (due to some technical problems which I reported earlier, I could not
> MM>> verify this detail yet)
>
> Ok.
>
> MM>> Back on client side, the data is handled by a JavaScript function.
>
> MM>> Let's take a look at a possible usage of a websocket with JSF 2.2 /
> Java EE 7:
> <div>
> Enter message:
> <h:inputText onkeypress="if (event.keyCode === 13)
> {acceptValue(this);}"/>
> <br/>
> </div>
> <h:inputTextarea id="messages" style="width: 100%; min-height: 10em;"/>
>
> MM>> A small JavaScript file is needed to establish the communication
> channel and
> MM>> to handle the client side sending and receiving part of the messages.
>
> var websocket;
>
> window.onload = function () {
> websocket = new WebSocket(obtainUri());
> websocket.onerror = function (evt) {
> onError(evt)
> };
> websocket.onmessage = function (evt) {
> onMessage(evt)
> };
> }
>
> function obtainUri(){
> return "ws://" + document.location.host + document.location.pathname +
> "chat";
> }
>
> function onError(evt) {
> writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
> }
>
>
> function acceptValue(element) {
> websocket.send(element.value);
> element.value = "";
> return false;
> }
>
> function onMessage(evt) {
> element = document.getElementById("messages");
> if (element.value.length === 0) {
> element.value = evt.data;
> } else {
> oldTexts = element.value.split("\n").slice(-19);
> element.value = oldTexts.join("\n") + "\n" + evt.data;
> element.scrollTop = element.scrollHeight;
> }
> return;
> }
>
> MM>> It is not very much code to broadcast a message from an input field
> to a
> MM>> textarea of all connected clients. Since I use JavaScript, I can
> implement
> MM>> any scenario like broacasting admin messages etc. This solution takes
> MM>> advance of the high performing open communication channel in both
> directions.
>
> MM>> Now, back to JSF 2.3 and <f:websocket>
>
> MM>> To distribute the received data, I need to implement some JavaScript
> code.
> MM>> Formerly, JSF tags could be used to hide all those non-Java stuff.
> MM>> Although I can use JavaScript by JSF.js to perform an ajax request,
> MM>> a common way is to hide this by using <f:ajax>. With respect to
> MM>> <f:websocket> such a JSF feature (hiding away JavaScript) is missing.
>
> As previously mentioned, now you can use f:ajax inside h:scriptWebsocket.
>
> MM>> And we can use <f:websocket> only to push data from server to client.
> MM>> Thus we can not take advantage of the faster channel from client to
> server.
>
> Well, it is not that simple. It is more accurate to say that JSF as a
> framework
> needs to keep a consistent view state. There is a queue on top of JSF ajax
> requests that serialize the requests sent to the server. If you send
> information
> from the client to the server using a websocket and that information
> changes
> the view, the view state could be in a inconsistent state later. Enforce
> ajax
> to communicate from the client to the server ensures consistency.
>
> What happens if you want to communicate from the server to the client and
> you
> don't need or dont change the view in the process? Well, you can imagine
> a "simplified" lifecycle, where the message is received on the websocket
> server
> side listener and then some action to process the message happens, but
> later
> you realize that the websocket channel is a view related concept. For
> example,
> if the view is destroyed, the associated websocket must be closed. The
> "properties" of h:scriptWebsocket are things that are initialized per view.
> The "listener" of the message in the server is something that should be
> defined in the tag as an EL expression, so it is in the view. Well, it is
> theoretically possible to do it, but it is not easy to do it.
>
> It could be something like:
>
> <h:scriptWebsocket channel="chat" onservermessage="#{...}"/>
>
> But at this point it is too late to do it. The problem is the EL
> expression
> requires a context to be evaluated properly, and the context is given
> by the view.
>
> MM>> I suggest optionally to connect the <f:websocket> to an input element
> MM>> as well to an output element, e.g.
>
> <f:websocket channel="xxx" user="yyy" input="idOfUiInputElement"
> output="idOfUiElement">
>
> MM>> input is optional whilst output is mutable exclusive with onmessage.
> Both
> MM>> attributes may point to the same element.
>
> MM>> For output we may define a behavior like "adds all messages",
> "replaces content
> MM>> with new message", "keeps last n messages".
>
> MM>> For the JavaScript fans, we may establish a mutual exclusive option
> to
> MM>> send data via the open channel.
>
> MM>> Thoughts?
>
> It doesn't look like something to include in the standard, or at least it
> is
> something that can be done in a third party library.
>
> regards,
>
> Leonardo Uribe
>
> 2017-01-04 2:04 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:
>
> Hi,
>
> Since m08 you can nest f:ajax into f:websocket. See also javax.faces.Push
> javadoc.
>
> As to user, yes indeed channels with same user attribute will receive the
> same message. And no, this value cannot be controlled by the client, if
> that was your concern.
>
> Cheers, B
>
> On Tue, Jan 3, 2017, 23:56 Michael Müller <michael.mueller_at_mueller-
> bruehl.de> wrote:
>
> Hi all,
>
> Here are some questions and thoughts about websocket:
>
>
> Technically, a websocket is an upgrade of the HTTP protocol which
> establishes a bidirectional communication channel between two peers. Once
> the connection is established it will be kept open until one of the peers
> closes it. Thus, it can be used to send any time any information (with
> respect to technical limitations) from any of both peers to the other.
> Because the channel is open all the time, this connection is faster than a
> series of HTTP request response cycles.
>
> Although a websocket establishes a channel between two peers, it is
> broadly used to broadcast information from one server to all clients. An
> example might be a chat room, where all individual user inputs are
> distributed to all (other) users. A simplified version of this scenario
> might be implemented using Java EE 7 like this:
>
> @OnMessage
> public void onMessage(String message, Session session) throws
> IOException, EncodeException{
> for (Session peer : peers) {
> peer.getBasicRemote().sendObject(session.getId() + ": " +
> message);
> }
> }
>
>
> Within JSF, we may send data from client to server at any time by
> initiating an ajax request.
> But, before JSF 2.3 there is no standard way to push information from
> server to client.
>
> Here <f:websocket> comes into play.
>
> Via @Push the developer may push information from server to client.
> If I understood it correctly, a send(message) will perform a broadcast,
> whilst .send(message, user) will send to a named user.
> What happens, if a couple of clients use the same value for user? Will it
> be a selective broadcast, e.g. like sending data to one of a couple of
> chatrooms?
> (due to some technical problems which I reported earlier, I could not
> verify this detail yet)
>
> Back on client side, the data is handled by a JavaScript function.
>
>
> Let's take a look at a possible usage of a websocket with JSF 2.2 / Java
> EE 7:
>
> <div>
> Enter message:
> <h:inputText onkeypress="if (event.keyCode === 13)
> {acceptValue(this);}"/>
> <br/>
> </div>
> <h:inputTextarea id="messages" style="width: 100%; min-height: 10em;"/>
>
> A small JavaScript file is needed to establish the communication channel
> and to handle the client side sending and receiving part of the messages.
>
> var websocket;
>
> window.onload = function () {
> websocket = new WebSocket(obtainUri());
> websocket.onerror = function (evt) {
> onError(evt)
> };
> websocket.onmessage = function (evt) {
> onMessage(evt)
> };
> }
>
> function obtainUri(){
> return "ws://" + document.location.host + document.location.pathname +
> "chat";
> }
>
> function onError(evt) {
> writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
> }
>
>
> function acceptValue(element) {
> websocket.send(element.value);
> element.value = "";
> return false;
> }
>
> function onMessage(evt) {
> element = document.getElementById("messages");
> if (element.value.length === 0) {
> element.value = evt.data;
> } else {
> oldTexts = element.value.split("\n").slice(-19);
> element.value = oldTexts.join("\n") + "\n" + evt.data;
> element.scrollTop = element.scrollHeight;
> }
> return;
> }
>
> It is not very much code to broadcast a message from an input field to a
> textarea of all connected clients. Since I use JavaScript, I can implement
> any scenario like broacasting admin messages etc. This solution takes
> advance of the high performing open communication channel in both
> directions.
>
> Now, back to JSF 2.3 and <f:websocket>
>
> To distribute the received data, I need to implement some JavaScript code.
> Formerly, JSF tags could be used to hide all those non-Java stuff. Although
> I can use JavaScript by JSF.js to perform an ajax request, a common way is
> to hide this by using <f:ajax>. With respect to <f:websocket> such a JSF
> feature (hiding away JavaScript) is missing. And we can use <f:websocket>
> only to push data from server to client. Thus we can not take advantage of
> the faster channel from client to server.
>
> I suggest optionally to connect the <f:websocket> to an input element as
> well to an output element, e.g.
>
> <f:websocket channel="xxx" user="yyy" input="idOfUiInputElement"
> output="idOfUiElement">
>
> input is optional whilst output is mutable exclusive with onmessage. Both
> attributes may point to the same element.
>
> For output we may define a behavior like "adds all messages", "replaces
> content with new message", "keeps last n messages".
>
> For the JavaScript fans, we may establish a mutual exclusive option to
> send data via the open channel.
>
> Thoughts?
>
> --
>
> Herzliche Grüße - Best Regards,
>
> Michael Müller
> Brühl, Germany
> blog.mueller-bruehl.de
> it-rezension.de
> @muellermi
>
>
> Read my books
> "Web Development with Java and JSF": <https://leanpub.com/jsf>
> https://leanpub.com/jsf
> "Java Lambdas and Parallel Streams":
> <http://www.apress.com/de/book/9781484224861>
> http://www.apress.com/de/book/9781484224861
> "Visitors" a photographic image book: <https://leanpub.com/visitors>
> https://leanpub.com/visitors
>
>
>
>