Hi
After thinking about the problem of ResourceHandler.createViewResource(),
I have an idea about how we can fix this part. Let's start for the
beginning (I'll do a small summary, fixing some parts to align the
concepts with the proposal, sorry if it becomes too repetitive):
According to the new spec, we have some special places that store view related
resources:
- META-INF/flows/<flow-name>/... : files there should be dealt as views.
- META-INF/contracts/<contract-name>/... : files there are not views but the
VDL should be able to load resources like templates that are used when a view
is processed. It also contains other resource files like .css, .png and so on
that the ResourceHandler should be able to locate and serve them. It also
contains composite component files.
- META_INF/resources/... : Contains resource files like .css, .png and so on
that the ResourceHandler should be able to locate and serve them. It also
contains composite component files.
Since we have 3 different concepts here, it should be 3 different methods to
deal with this:
- ResourceHandler.createResource(...) : (simplifying) resources loaded
using this method should scan these locations:
* META-INF/contracts/<contract-name>/... in the classpath
* META_INF/resources/... in the classpath
* /resources/... in webapp folder
- ResourceHandler.createViewTemplateResource(
FacesContext context, String resourceName) : load template files from
these locations:
* /... in webapp folder
* META-INF/contracts/<contract-name>/...
- ResourceHandler.createViewResource(
FacesContext context, String resourceName) : load files from these
locations:
* /... in webapp folder
* META-INF/flows/<flow-name>/...
Note it is necessary to define ordering of precedences here, but I'm
suggesting do it in this way.
How a facelet resource should be loaded?
- If the vdl is building a view by first time, call createViewResource(...).
- If a template is being loaded, call createViewTemplateResource(...).
- If a template is being loaded AND the call is relative,
call createViewTemplateResource(...).
- If a template is being loaded AND it is called from a composite
component or comes
from a composite component AND the call is absolute use
createViewTemplateResource(...).
- If a template is being loaded AND it is called from a composite
component or comes
from a composite component AND the call is relative, use createResource(...).
using the libraryName from the composite component (if any).
- If a composite component is being loaded, use createResource(...).
To resolve a relative reference of a template, the suggested way is use the
"nearest parent" libraryName and the base "resourceName" or "path" of the
parent template.
The proposal also suggest that Resource instances loaded from resource library
contract path has precedence over anything, which means if there are two
resources:
META-INF/contracts/contractA/x.css
and
META-INF/resources/x.css
In a call to createResource("x.css"), the instance returned will be the one
inside contracts. But the other side of the coin is that templates resolved
in a relative way can be overriden from a resource library contract, which
doesn't sound good, so maybe the precedence in createResource("...") should
be changed (it is up to you guys to decide which alternative is better).
Note the solution proposed has effects like that in theory it is possible
to create a composite component inside a resource library contract.
regards,
Leonardo Uribe
2013/1/16 Leonardo Uribe <lu4242_at_gmail.com>:
> Hi Frank
>
> 2013/1/16 Frank Caputo <frank_at_frankcaputo.de>:
>> Hi Leonardo,
>>
>> Am 15.01.2013 um 20:37 schrieb Leonardo Uribe <lu4242_at_gmail.com>:
>>
>>> Thinking about this, I think a good idea could be add a method to
>>> Resource interface to get the last modified time.
>>>
>>> public Long getLastModified()
>>>
>>> return null if no lastModified time can be returned.
>>
>> This method would be really helpful, but I wouldn't allow null to be returned, so I'd use the primitive long as return value.
>>
>
> Ok. good to know that. The idea of the null is to know when there is
> no lastModified time, but maybe a -1 is better.
>
>> There will be an issue with decorating existing resources and overwriting only getLastModified. userAgentNeedsUpdate and getResponseHeaders won't call the decorated version of getLastModified. So on decorated resources all 3 methods must be implemented, which is not very comfortable.
>>
>
> The same hypotethical issue exists between userAgentNeedsUpdate and
> getResponseHeaders too, but the important consideration is how often
> is required to modify the last modified time? For "static" resources
> it will be always the same value, so the wrapper will not modify them.
> For resources that needs to be generated once (css + inner EL
> expressions), the same consideration applies (will not be modified).
> Resource instances like the one required by a captcha component (an
> image that is generated in a unique way per session), will have
> different implementations in those methods (usually getResponseHeaders
> return null userAgentNeedsUpdate return true and getLastModified
> return 0 or -1).
>
> In conclusion, in my opinion we shouldn't worry about that detail,
> because once these methods are defined, by the "nature" of the
> underlying Resource those implementations does not change.
>
>> Ciao Frank
>>
>>> 2013/1/15 Frank Caputo <frank_at_frankcaputo.de>:
>>>> Hi Leonardo,
>>>>
>>>> I recently provided a patch for Mojarra to solve this problem, which Manfred merged into the trunk ( http://java.net/projects/mojarra/sources/svn/diff/trunk/jsf-ri/src/main/java/com/sun/faces/facelets/impl/DefaultFacelet.java?rev1=11384&rev2=11385 ).
>>
>> Does this answer obsolete your older comments on resource library contracts?
>>
>
> No. I think use the alias for the calculation is not the right way to
> do it, because the alias has another different meaning. For example,
> in MyFaces the alias is prefixed according if is a facelet, view
> metadata facelet or a composite component facelet. If I remember well,
> the alias was used in the id generation, but I changed that part in
> MyFaces with a better concept ( faceletId ). So, in MyFaces at the end
> the "alias" is used only as debug information.
>
> In this case, DefaultFacelet must be modified to store the contextual
> library / resource and use that information to derive a relative
> resource. Suppose a composite component located in
> META-INF/resources/my.composite.component/simplecc.xhtml . It there is
> a reference to
>
> <ui:include src="dir1/resource.xhtml"/>
>
> The resource should be located in:
>
> libraryName: my.composite.component
> resourceName: dir1/resource.xhtml
>
> Going back to the base example, if there is a file under
> /templates/b.xhtml with a reference to:
>
> <ui:decorate template="dir2/mytemplate2.xhml">
>
> The resource should be located in:
>
> libraryName: N/A
> resourceName: /templates/dir2/mytemplate2.xhtml
>
> Note if there is a resource in
> META-INF/resources/templates/dir2/mytemplate2.xhtml, the resource
> should not be taken into account (or maybe yes), because what we want
> is resolve the resource in a relative way. The resolution process
> inside a composite component is different than the resolution from a
> template, but if the call is located inside a template called from a
> composite component, it is relative to the composite component
> library.
>
> Really this part is still open to interpretation, and it is clear we
> need to get to an agreement about how this should work.
>
> regards,
>
> Leonardo Uribe
>
>> Ciao Frank
>>
>>>>
>>>> I'll answer more detailed tomorrow.
>>>>
>>>> Ciao Frank
>>>>
>>>> Am 15.01.2013 um 00:32 schrieb Leonardo Uribe <lu4242_at_gmail.com>:
>>>>
>>>>> Right now, facelets derive the path using a call to:
>>>>>
>>>>> new URL(from, path)
>>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>
>>
>>
>>
>>