myfaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Leonardo Uribe <lu4...@gmail.com>
Subject Re: [proposal] A new module for improved JSF-MVC inside MyFaces Project
Date Thu, 08 May 2014 15:35:06 GMT
Hi

Ok, I think the idea about @ViewAction and @ViewParam is clear, I have
implemented a fast prototype and it works well, there is a lot of things we
can do for improvement, however we should focus the attention in other
areas so we can give the module a better structure.

The next thing we need is how to combine javascript with JSF, specifically
in cases like this:

<input id="search"/>
<script type="text/javascript">
    $('#search').autocomplete({
        source: "#{some EL that return a link to an action goes here}"
    });
</script>

The idea is provide an input box and then write some javascript lines to
make the component an autocomplete box, but the problem is we need to provide
a URL that can be used to retrieve the values to fill the box. In my opinion,
mix EL and javascript is the best in these cases, but things get complex
quickly when you need to provide parameters and so on. So I would like to
propose these facelet functions (better with examples):

    <a href="#{ma:getLink('mypage?action=exportExcel')}">Export excel</a>

and

    <ma:defineLink id="mylink">
        <f:param name="action" value="renderMessage"/>
    </ma:defineLink>

    <a href="#{ma:getLinkFrom('mylink')}">Render url from EL expression</a>

#{ma:getLink(...)} work just like h:link but receives the outcome as parameter.
The function append the request path and the client window id, so the final
generated link will be something like this:

http://localhost:8080/myfaces-mvc-examples/sayhello.jsf?id=5&jfwid=1di8uhetf9&action=exportExcel

#{ma:getLinkFrom(...)} just inject the link from a component that works just
like h:link but it is just a wrapper, so the user can customize the parameters,
when the EL function is called, the link is rendered taking the parameters
in the definition. The outcome by default is the page itself.


Please note this proposal is something different from the one that suggest to
create the link just pointing to the method in the bean like
#{ma:getLink('mybean', 'mymethod', params)}. After thinking about it, the
problem with that approach is the difficulty to do the match between the link
to generate and the method. EL does not consider annotated methods, so it is
not possible to scan the annotations from the EL unless you do a bypass over
CDI.

I think the approach proposed is something simple to understand, and it has
the advantage that you can isolate the declaration of the link from the
rendering, so the final javascript code will be easier to read.

Finally we need something for the POST case, so the idea is append something
like this:

    <form action="#{ma:encodeActionURL()}"
          method="post"
          enctype="application/x-www-form-urlencoded">
        ....
    </form>

#{ma:encodeActionURL()} do what h:form does for encode the action url. Then,
it is responsibility of the user to provide the view state and client window
token in the request as data, so the postback can be processed properly.
In this case, the idea is the view scope will be available, but the component
tree state will not be updated when POST goes back to the client, so any
changes on the component tree in the action will be ignored.

JSF does not make any difference between GET and POST, so viewParam will
work just the same. What defines a postback in JSF is if the view state
field is in the request or not. Theoretically, use #{ma:getLink(...)} should
work too, but I think there are different cases.

There is a contradiction in this case. Send a POST, provide the view state
token, do not restore the view but restore the view scope bean. The problem is
after you make changes on the view scope beans you need to save those changes,
and that could mean update the view state token, even if the beans are stored
in the server (remember the beans can be serialized, for example in a cluster).

If we take a look at the proposed goals:

1) possibility to use a normal JSF lifecycle for the first GET request
2) allow action handling and custom response for POST actions
3) normal action handling like in asp.net MVC + a EL util function to
generate the action URL

we cannot really make number 2 exactly as POST actions. It doesn't fit because
"... JSF’s core architecture is designed to be independent of specific
protocols and markup. ...".

Really the problem proposed in number 2 is not simple and we should analyze it
carefully. In which cases do we really need that kind of action handling? If
we are thinking for example in a JSF component that defines an endpoint with a
custom response (for example a captcha component), we need a component oriented
solution, something closer as what we have for ajax. What we have proposed
here with @ViewAction works in the case the user needs to define an endpoint
at the "page" level.

Really the big problem is how to hook the javascript code, so the updates of
the view state on the client side can be properly chained. For example in
MyFaces there is a queue for all ajax request, but we need that the actions
sent that requires update the view state can be synchronized with that
ajax queue too.

I think what we have already is enough useful for a module. After all, we
don't need to solve all the problems at once.

Suggestions are welcomed.

regards,

Leonardo Uribe

2014-05-05 0:05 GMT+02:00 Leonardo Uribe <lu4242@gmail.com>:
> Hi Thomas
>
> TA>> AFAIR now, your solutions seems to be just a replacement for f:viewAction
> TA>> + allow different handlers via URL parameters.
> TA>> Its sound really lightweight and easy actually :)
> TA>> Does it cover all our requirements from the earlier mails?
> TA>>
>
> I think so, but we need to write some examples to be sure that the syntax cover
> all cases.
>
> Instead put a Front Controller on top of the lifecycle, we can go with
> this approach
> and provide some methods to call JSF algorithm inline. We already have some
> code in VDL.createComponent(...) that does inline compilation, so it
> is not really
> hard to write the necessary lines to do so (if the code is properly implemented
> of course). The idea could be provide something like:
>
> JSFUtils.generatePage("/mypage.xhtml", ....)
>
> and internally we call the algorithm, and deal with the potential problems.
>
> So, if the user really wants to go with a MVC framework and use JSF as template
> engine, it will be as simple as write the adapter for the framework.
> We should not
> reinvent the wheel in this case. So, all other cases not supported by
> f:viewAction/f:viewParam, which should be very, very few, should be done writing
> a servlet or using an MVC framework like JAX-RS, and if necessary calling
> JSF at render time.
>
> The nice part about reuse f:viewAction logic is that is something
> proved, everybody
> knows how it works, we are just extending the syntax to define f:viewAction in
> a more familiar way. In practice we need to write a custom component extending
> UIViewAction, but that's something easy, I have already done it and it works.
>
> That should cover most of the cases. There are other cases that are indirectly
> related to this one, but after some review, it doesn't seem to be so interesting
> or useful, or can be too complex to implement properly, so we need to
> wait and push
> it into the next spec. Sometimes less is more. Let's see what happen.
>
>>> Whats the syntax for multiple params? ->
>>> params="action=exportExcel&someOther=string"?
>>> Maybe we could think about a more typesafe and readable way. e.g.
>>>
>>> @ViewAction(value="my.xhtml", params = {
>>>      @ViewParam(name="action", value="exportExcel"),
>>>      @ViewParam(name="someOther", value="string")
>>> })
>
> I was thinking about this:
>
>     @ViewAction(value="/sayhello.xhtml", params="action=exportExcel")
>     public void method3(@ViewParam String param1,
> @ViewParam("someOther") Integer param2)
>     {
>
> The method has two parts: one define the parameters that should be present
> and the other define the activation conditions, in this case, when
> action=exportExcel. Please note to make @ViewParam("someOther"), we
> need to associate value to the key name. So we could do something
> like this:
>
>     @ViewAction(value="/sayhello.xhtml",
>                           params= {
>                                @ViewParam(name="action",
> expectedValue="exportExcel")
>                           })
>     public void method3(@ViewParam String param1,
> @ViewParam("someOther") Integer param2)
>     {
>
> I think in this way it looks better. Thanks for the suggestion.
>
> regards,
>
> Leonardo

Mime
View raw message