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

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

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Wed, 28 Sep 2016 12:18:47 -0500

Hi

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

I don't understand why. If no name is provided, the user must provide an id:

<h:commandScript id="script1"
                 action="#{bean.pushed}"
                 render="foo" />

And then you can use EL to get the generated function name:

#{f:getCommandScriptName(component, 'script1')}

According to the javadoc, "name" is not a required attribute and "id" is a
valid attribute, but there is no way to get the function name.

regards,

Leonardo


2016-09-28 0:59 GMT-05:00 Bauke Scholtz <balusc_at_gmail.com>:

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