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

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

From: Bauke Scholtz <balusc_at_gmail.com>
Date: Wed, 28 Sep 2016 07:59:45 +0200

Hi,

A generated name for h:commandScript makes it unusable for its originally
intented purpose.

Cheers, B

On Wed, Sep 28, 2016 at 7:50 AM, Leonardo Uribe <leonardo.uribe_at_irian.at>
wrote:

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