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

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: Re: improvements to f:websocket and PushContext

From: Bauke Scholtz <balusc_at_gmail.com>
Date: Tue, 27 Sep 2016 08:54:04 +0200

Hi,

The primary purpose of h:commandScript is to have the ability to invoke a
JSF managed bean method via native HTML DOM events and JavaScript. Usually
the users who would use it are already well versed with JavaScript. It
offers a lot of flexibility. See also this related Q&A:
http://stackoverflow.com/q/16588327 In my humble opinion, the uniqueness of
the function name is not "our" concern. If really necessary, you can just
inline EL in the name attribute.

Using websocket in a composite feels wrong. That's not what composites are
for and a websocket is really "view metadata". I'd rather recommend to use
only one which does its job based on method arguments. This is also
elaborated in o:socket Javadoc:
http://omnifaces.org/docs/javadoc/2.5/org/omnifaces/cdi/push/Socket.html#channels


The f:websocket+f:ajax combination is certainly more natural and doable. It
only feels wrong to turn the f:websocket into an UIComponent, again because
it is really "view metadata". We shouldn't encourage users to have many of
them in the same view. The f:websocket doesn't generate any markup, only a
script tied to the document. I'm more tempted to utilize the
ClientBehaviorHolder nature of the HtmlBody in some way.

Cheers, B




On Tue, Sep 27, 2016 at 3:04 AM, Leonardo Uribe <leonardo.uribe_at_irian.at>
wrote:

> Hi
>
> NOTE: This mail is going to be a bit repetitive, but it is necessary in
> order to digest this topic properly. Thanks for your patience.
>
> According to the latest javadoc I can see, h:commandScript is a component
> with the same attributes as f:ajax (without 'event') with some new ones:
>
> - action
> - actionListener
> - immediate
> - rendered
> - value
> - autorun
> - name
>
> So, I guess the intention is to work like something between a UICommand and
> Ajax, but it looks like h:commandScript is something that has life on its
> own, just like s:jsCallbackFunction has. It is a component that renders an
> script function with some jsf behavior in it but without "get your
> hands dirty" with javascript code.
>
> Let's take a look again at the syntax proposed:
>
> <f:websocket ... onmessage="someCommandScript" />
>
> <h:commandScript name="someCommandScript"
> action="#{bean.pushed}"
> render="foo" />
>
> If "name" is the fixed javascript function name, you can't use this inside
> a composite component or multiple times on the page. There is a 1-1
> relationship between f:websocket and h:commandScript, because you can't use
> the name more than once in a page. You can improve it using this:
>
> <f:websocket ... onmessage="#{f:getCommandScript(component, 'script1')}"
> />
>
> <h:commandScript id="script1" name="someCommandScript"
> action="#{bean.pushed}"
> render="foo" />
>
> use an EL function that generate the function name using the id, it is like
> a findComponent call that locate the h:commandScript component and from
> its cliendId it replace all invalid characters (':') with '_' .
>
> The script could be generated in this way:
>
> <script type="text/javascript">
> var form_panel_script1 = function(){
> jsf.ajax.request(...);
> }
> </script>
>
> Ok, that improve things a little bit, now I can use it inside composite
> components, more than once per page but there is still a 1:1 relationship
> between f:websocket and h:commandScript. You can't use more than one
> h:commandScript with a f:websocket. Do you have 5 or 6 regions in your
> page
> that needs to be updated from the server? you need 5 or 6 f:websocket with
> the same number of h:commandScript tags.
>
> I understand that this approach provides flexiblity and that's ok, but it
> looks way too complex, for a simple use case where the user only wants to
> refresh a component from the server.
>
> Take a look at one possible example with p:socket tag:
>
> <p:socket channel="/channel">
> <p:ajax event="message"
> listener="#{controller.yourListenerMethod}"
> update=":form:table" />
> </p:socket>
>
> I'm not surprised somebody else has already thought the same. If the soul
> of the spec is standarize common practices, this looks like something
> common and easy to understand. Note in this case the "event" property
> is not used as I have thought, which is something like this:
>
> <f:websocket channel="ping" messageEvent="true">
> <f:ajax event="updateInfoBox" render="myInfoBox"/>
> <f:ajax event="updateMessageBox" render="myMessageBox"/>
> <f:ajax event="update" render="myMessageBox myInfoBox"/>
> </f:websocket>
>
> where you can use 1 websocket connection to update 1, 2 or more components
> using "event" as the payload for the push. Please note a new possible
> attribute called "messageEvent" that could enable the behavior wanted,
> but maybe the presence of 2 or more f:ajax could enable it.
>
> Other way to see the problem is think about f:websocket, h:commandScript
> and f:ajax together:
>
> <f:websocket id="wschannelping" channel="ping">
> </f:websocket>
>
> <h:commandScript forwebsocket="wschannelping"
> actionListener="#{bean.update}">
> <f:ajax event="updateInfoBox" .../>
> </h:commandScript>
>
> In that sense, h:commandScript register itself in f:websocket in a dynamic
> way, as if f:websocket could have a built-in "Command Pattern". You can
> notice that h:commandScript is a component that "by default" has an
> embedded f:ajax tag, because you can't call the actionListener without an
> ajax request. But maybe this mode is too much, the component lookup is too
> complex.
>
> At last, in conclusion, in my personal opinion, the proposal could be:
>
> - Allow f:websocket and f:ajax work together (f:websocket is a component
> implementing ClientBehaviorHolder).
> - Add a mode with a property called "messageEvent" or whatever, by default
> false, that if it is set to true, binds the pushed message with f:ajax
> event
> property and use it to "demux" the notification and invoke the right ajax
> request.
> - Use a generated function name based on the clientId in h:commandScript
> and
> an EL function to calculate it.
>
> Suggestions are welcome.
>
> regards,
>
> Leonardo Uribe
>
> 2016-09-26 6:41 GMT-05:00 Josh Juneau <juneau001_at_gmail.com>:
>
>> +1...I agree. Individuals already understand the way that <f:ajax>
>> functions, so it makes sense to use it if possible.
>>
>> Josh Juneau
>> juneau001_at_gmail.com
>> http://jj-blogger.blogspot.com
>> https://www.apress.com/index.php/author/author/view/id/1866
>>
>>
>> On Mon, Sep 26, 2016 at 5:38 AM, Kito Mann <kito.mann_at_virtua.com> wrote:
>>
>>> +1 for adding <f:ajax> support to <f:websocket>. I believe PrimeFaces
>>> does this with <p:socket>, and it's certainly more intuitive than hooking
>>> it up to <f:commandScript>.
>>>
>>> ___
>>>
>>> Kito D. Mann | @kito99 | Author, JSF in Action
>>> Web Components, Polymer, JSF, PrimeFaces, Java EE, and Liferay training
>>> and consulting
>>> Virtua, Inc. | virtua.tech
>>> JSFCentral.com | @jsfcentral | knowesis.io
>>> <http://knowesis.io/web/webcomponents> - fresh Web Components info
>>> +1 203-998-0403
>>>
>>> * Listen to the Enterprise Java Newscast: *http://
>>> <http://blogs.jsfcentral.com/JSFNewscast/>enterprisejavanews.com
>>> <http://ww.enterprisejavanews.com>*
>>>
>>>
>>> On Sun, Sep 25, 2016 at 11:55 AM, Bauke Scholtz <balusc_at_gmail.com>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> h:commandScript is result of https://java.net/jira/browse/J
>>>> AVASERVERFACES_SPEC_PUBLIC-613 See also
>>>> http://arjan-tijms.omnifaces.org/p/jsf-23.html for others.
>>>>
>>>> I do understand the h:commandScript limitation in portlet case, but in
>>>> a portlet app there's also only one JavaScript context.
>>>>
>>>> I have to admit that the f:websocket+f:ajax looks more natural. I will
>>>> try creating a POC on this. I only don't like the idea of turning the
>>>> f:websocket from TagHandler into UIComponent. It's really kind of view
>>>> metadata.
>>>>
>>>> Cheers, B
>>>>
>>>>
>>>>
>>>> On Sat, Sep 24, 2016 at 3:53 AM, Leonardo Uribe <
>>>> leonardo.uribe_at_irian.at> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> I see, so this is hidden in the spec. Thanks for mention it.
>>>>>
>>>>> I have to say I can see a problem with this structure, and it is
>>>>> related to the "name" used on the script.
>>>>>
>>>>> In JSF each component has it own clientId that is calculated somehow.
>>>>> So according to the location of the component inside the tree, the clientId
>>>>> is generated.
>>>>>
>>>>> The way how clientId works ensures the component can be relocated to
>>>>> different parts of the tree and it will still work.
>>>>>
>>>>> The problem with a hardcode name is that you lose this property in the
>>>>> code. If you are in a portlet case, I can see that if the same component is
>>>>> used twice on different portlets, the page will crash by a duplicate
>>>>> definition.
>>>>>
>>>>> There is a component in tomahawk sandbox that try this and it is
>>>>> called s:jsCallbackFunction . Remember the component is in sandbox, so in
>>>>> that sense it is experimental.
>>>>>
>>>>> * This component creates a function inside an inline &lt;script&gt;
>>>>> tag,
>>>>> * with a function that can be referenced later using
>>>>> getFunctionName() method
>>>>> * inside this component instance or the EL function
>>>>> #{s:jsCallbackFunctionName(UIComponent)}.
>>>>> * <p>
>>>>> * Inside the function, the following code is added:
>>>>> * </p>
>>>>> * <code>
>>>>> * generatedFunctionNameUsingClientIdAndEventName = function (...
>>>>> arguments ...){
>>>>> * ... jsStartContent ...
>>>>> * ... clientBehavior scripts ...
>>>>> * ... jsEndContent ...
>>>>> * }
>>>>> * </code>
>>>>> * <p> This is useful in situations where the context where this
>>>>> script is
>>>>> * rendered is important, and it is not possible to put the scripts on
>>>>> static
>>>>> * javascript files.</p>
>>>>>
>>>>> What I mean is with an EL function it is possible to generate the
>>>>> function name based on the clientId of the component and avoid the problem
>>>>> h:commandScript has.
>>>>>
>>>>> Let me be clear about this: the way how h:commandScript works right
>>>>> now creates a conflict for portlet case, and I do not want to create
>>>>> another one after spend a lot of time trying to solve
>>>>> JAVASERVERFACES_SPEC_PUBLIC-790.
>>>>>
>>>>> The way how h:commandScript and f:websocket interact should be more
>>>>> subtle. If f:websocket is a component with an id, it should be possible to
>>>>> reference it so you could "declare" a h:commandScript to be called for
>>>>> f:websocket. So, with one f:websocket it should be possible to call many
>>>>> h:commandScript functions.
>>>>>
>>>>> I think we should focus our efforts in create a syntax easy to
>>>>> understand, that solve the problem of update parts of the view after an
>>>>> event triggered on the server.
>>>>>
>>>>> regards,
>>>>>
>>>>> Leonardo Uribe
>>>>>
>>>>>
>>>>> 2016-09-23 16:01 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> It has already been thought about, it can be combined with
>>>>>> h:commandScript, also new in JSF 2.3.
>>>>>>
>>>>>> <f:websocket ... onmessage="someCommandScript" />
>>>>>> <h:commandScript name="someCommandScript" action="#{bean.pushed}"
>>>>>> render="foo" />
>>>>>>
>>>>>> The message will transparently be available as request parameters in
>>>>>> associated bean.
>>>>>>
>>>>>> Cheers, B
>>>>>>
>>>>>> On Fri, Sep 23, 2016 at 9:22 PM, Leonardo Uribe <
>>>>>> leonardo.uribe_at_irian.at> wrote:
>>>>>>
>>>>>>> Hi
>>>>>>>
>>>>>>> I have been thinking about the way how f:websocket / PushContext
>>>>>>> works, just trying to see what's missing or another way to see this
>>>>>>> feature, to see if we can make it better.
>>>>>>>
>>>>>>> Even if f:websocket behavior is well understood and very flexible
>>>>>>> the way it is, what bothers me about it is this feature is too javascript
>>>>>>> specific. What I mean is you always need to write a javascript block to
>>>>>>> handle the incoming processing.
>>>>>>>
>>>>>>> But sometimes what you really want is update a part or just an
>>>>>>> specific component in the view. In other words, sometimes the web socket is
>>>>>>> only used as way to notify the view that something has changed on the
>>>>>>> server and the view needs to be updated somehow.
>>>>>>>
>>>>>>> In other words, sometimes the user doesn't want to override
>>>>>>> onmessage and instead just say update component xxx or yyy.
>>>>>>>
>>>>>>> For example, imagine the following syntax:
>>>>>>>
>>>>>>> <f:websocket channel="ping">
>>>>>>> <f:ajax event="update" render="myInfoBox"/>
>>>>>>> </f:websocket>
>>>>>>>
>>>>>>> On the server the update is triggered using this:
>>>>>>>
>>>>>>> @Inject
>>>>>>> @Push(channel="ping")
>>>>>>> private PushContext push;
>>>>>>>
>>>>>>> ....
>>>>>>>
>>>>>>> push.send("update");
>>>>>>>
>>>>>>> Now, f:websocket looks more like a component that implements
>>>>>>> ClientBehaviorHolder than a tag, and the "default" onmessage is a method
>>>>>>> that takes the message and if the event match the message it triggers the
>>>>>>> related f:ajax script.
>>>>>>>
>>>>>>> In html markup, f:websocket should create a html tag with the
>>>>>>> associated custom events.
>>>>>>>
>>>>>>> What do you think guys about it? does it work? is it useful? is it
>>>>>>> worth?
>>>>>>>
>>>>>>> regards,
>>>>>>>
>>>>>>> Leonardo Uribe
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>