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

[jsr372-experts] Re: [jsr372-experts mirror] Re: Re: Re: Url mapping

From: Leonardo Uribe <leonardo.uribe_at_irian.at>
Date: Thu, 13 Nov 2014 15:08:26 -0500

Hi

EB> Leonardo, I share your skepticism of the merits of this proposal.
EB> Especially when we consider that we could propose something to the
EB> servlet EG, the broad changes included in this proposal require much
EB> more refinement and discussion, and prototyping.

I just want to put all the elements on the table, to get a clear idea
about the trade-offs.

EB> My first impression is that this idea would be better served in the MVC
EB> spec.

I think JSF has some special requeriments that we need to consider:

- It is necessary to generate urls based on the mapping information.
- It is necessary to interpret the url later and transform it to
produce a "normalized" form that can be processed by JSF.
- The mapping must be calculated on application startup.

I think it fits better in JSF, because we need to control some steps
inside JSF.

AT> The arguments are not that different from what CDI extensions do. The
AT> CDI runtime scans through an amazing amount of classes and calls an
AT> arbitrary amount of extensions, potentially for each and every class
AT> encountered. Extensions may do expensive and time consuming things
AT> like scanning for custom annotations and accessing things via
AT> reflection.

As far as I know, CDI does not load the classes, it just scan them with a
flat scanner, that does not load any class. Here we are talking about
"parse" xml files, create a UIViewRoot and the metadata tree (without
a UIViewRoot, there is no metadata), and finally grab the metadata. That
parsing forces to load every class related to every component used in
the application.



I would like to do a counter-proposal.

Suppose there is a special web folder called META-INF/views. It has
the following conditions:

- Every file there will be mapped to an extensionless url without
exception, no questions asked.
- If a file name or a folder name contains '{...}', it means that
this part of the url is a path param that is transformed later to a
query param. Note '{' and '}' are considered "unwise" characters
on a url, so nobody uses it, but are valid characters for file names
in windows and linux systems.
- JSF specify that at startup it will scan all files inside that
folder and based on that (just read the file name) it will build a
mapping tree and update the servlet mappings.
- Any directory inside META-INF/views has the same logic used in
Faces Flows, so you can define flows here too.
- URL mapping can be done inside faces-config.xml too.

Example:

webapp
|-- WEB-INF
| |-- web.xml
| +-- faces-config.xml
|-- META-INF
     |-- views
          |-- books
               |-- {bookId}.xhtml
               |-- {bookId}
                    +-- showAuthors.xhtml


This is how JSF map the information:

/books/{bookId}.xhtml maps to
http://localhost:8080/myapp/books/1

/books/{bookId}/showAuthors.xhtml maps to
http://localhost:8080/myapp/books/1/showAuthors

Let's review the five point list you suggest:

1. Default mapping of FacesServlet to .xhtml

We need a method on ViewDeclarationLanguage, for example
VDL.handleViewId(FacesContext facesContext, String viewId)
that just check if the viewId (/books/{bookId}.xhtml) can be
handled by the VDL, without check if the resource exists
(VDL.viewExists()). The algorithm could iterate over all
VDL available.

2. Plain extensionless mapping
3. Extensionless mapping + availability of path info

JSF should not see the incoming URL. Instead it just see the
viewId and some extra parameters created by the url mapping
algorithm, that can be handled as view params.

http://localhost:8080/myapp/books/1

will be seen in JSF as:

viewId: /books/{bookId}.xhtml
requestParam: bookId = 1

inside {bookId}.xhtml

<f:metadata>
    <f:viewParam name="bookId" value="..."/>
</f:metadata>

To generate a link you should write inside the page:

<h:link outcome="books">
    <f:param name="bookId" value="1">
</h:link>

<h:link outcome="books/showAuthors">
    <f:param name="bookId" value="1">
</h:link>

Note you need to know the params defined to calculate the right
outcome, so we need some changes over navigation algorithm.

It can be done in different ways. A decorator over ExternalContext,
an ViewURLMapper/ViewURLMapperFactory class that decouple the
mapping logic we have in JSF 2.2 section 2.2.1.

4. Rules based URL mapping with simple pattern based rules
5. Rules based URL mapping with rewrite rules of arbitrary complexity

I would like to ask you guys a question: How much flexibility is required?
Could it be that a simple path param mapping is all that we need?.

We can provide further flexibility using some kind of pattern
matching, but I doubt about its usefulness. Most of the time what the
developers want is introduce a param in the url and use the same view
for multiple urls.


In my personal opinion, the proposal has the following advantages:

- Provide an abstraction that hides how the urls are generated.
- Hide how the urls are generated allow use the same logic in different
situations with no changes. For example, portlets can just provide
its custom url mapping approach on top of the existing one. The
application will work in any case
- Reuse existing logic in JSF.
- You can take a look at the file tree and in one shot you can
see the url mapping structure of your application. No need to open extra
files.
- You don't need to compile .xhtml files, create component trees.
It will be a small hit on application startup, a new SPI interface to
give the server the option to list the files and that's it.
- It would be possible to bundle an entire application inside a jar,
because we will have a way to add views to an application.
- It could be possible to secure the valid view urls of an application.
Using some config inside faces-config.xml, define a check to do before
or after the view is loaded to check if it is valid to show the view
or not and if not deal with it. This logic is usually scattered inside
ViewHandler.

Suggestions are welcome.

regards,

Leonardo Uribe


2014-11-11 12:02 GMT-05:00 arjan tijms <arjan.tijms_at_gmail.com>:
> Hi,
>
> On Mon, Nov 10, 2014 at 11:51 PM, Edward Burns <edward.burns_at_oracle.com> wrote:
>> Especially when we consider that we could propose something to the
>> servlet EG, the broad changes included in this proposal require much
>> more refinement and discussion, and prototyping.
>
> I think it does depend a little on how far we're willing to take this.
> There seem to be several ideas floating around, all somehow related to
> the topic of "mapping". With an increasing level of complexity these
> seem to be:
>
> 1. Default mapping of FacesServlet to .xhtml
> 2. Plain extensionless mapping
> 3. Extensionless mapping + availability of path info
> 4. Rules based URL mapping with simple pattern based rules
> 5. Rules based URL mapping with rewrite rules of arbitrary complexity
>
> Option 1. is completely trivial to implement, but really only makes
> sense when it's a default mapping.
>
> Option 2. is more involved, but as far as rule processing goes also
> trivial, since there's no user provided rule to speak off. It's
> completely convention and defaults based. If someone wants a
> /book/edit there needs to be a folder "book" with a view "edit.xhtml".
>
> Option 3. is like option 2, but just like Servlets had from day one,
> adds the ability to expose the extra paths after the resource mapping.
> E.g.:
>
> /foo/bar is requested
> /foo/bar.xhtml doesn't exist, but /foo.xhtml does
> Instead of sending a 404, use /foo.xhtml, preferably with "/bar" as
> request.getPathInfo()
>
> This rather useful feature is known in the Apache HTTPD+PHP world
> known as "MultiViews".
>
> Option 4. and especially 5. are slowly getting more complicated. What
> syntax do we allow? Only simple name mapping ("foo" maps to "bar") and
> simple path to parameter mapping? E.g. /12 becomes userid=12 Or do we
> have PrettyFaces/Rewrite-like rules, which if I'm not mistaken are of
> nearly arbitrary complexity?
>
> Kind regards,
> Arjan Tijms