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

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

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Wed, 28 Sep 2016 00:50:03 -0500

Hi

2016-09-27 1:54 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:

> 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.
>
>
Thanks for mention the purpose of h:commandScript, it help to clarify its
objective.

The change proposed does not change the way how h:commandScript works right
now. Instead, we could use "name" property and if no name is defined, use
the generated one, but provide a way to get the right one using EL.

I think JSF spec should enforce good coding practices and avoid situations
like this one, where the user needs to think about this. Please note the
user can still inline EL in the name, but the other one has the advantage
that the generated name will be aligned to the clientId, which is something
that will always work well. This is like the dilemma between global
variables and scoped variables. Both will work but only scoped variables
ensures no conflicts.

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
>
>
To use the same language and avoid confusions, in my point of view, "view
metadata" is all the information that is necessary to create the view and
give it "shape", like its path, locale, contracts, parameters, actions and
so on. This info is calculated on restore view phase. The "view body" is
build when vdl.buildView is called.

What I believe you are saying is websockets are defined as a view level
concept, not a component level concept. Well, yes and no. The problem as I
understand is there is some data on the server and you need to notify
changes over these data to the client. The "channel" defines the data sets
available on the server and the scope this data sets belongs to. This data
sets are associated with parts of the view, which are rendered by different
components. But there is no rule about how you organize the different parts
of your applications. You use templates, composite components or whatever,
and f:websocket could not necessary be a the top level, or your app could
have more than one f:websocket declaration.

To be clear, if something is not inside f:metadata or is not an attribute
of f:view, is not view metadata. But can be a "view related" concept.


> 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.
>
>
f:viewParam, f:viewAction are both descendants of UIComponent and are both
view metadata. In fact, for me it does not matter how it is in code as long
as the syntax is supported.

I agree we should find ways to reduce the use of many of them on the same
view. That's why I thought about send the "event" in the message and use
that to map different f:ajax or client behaviors.

regards,

Leonardo


> 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
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>