Issue Details (XML | Word | Printable)

Key: JAVASERVERFACES_SPEC_PUBLIC-947
Type: New Feature New Feature
Status: Open Open
Priority: Minor Minor
Assignee: Unassigned
Reporter: Ed Burns
Votes: 24
Watchers: 5
Operations

If you were logged in you would be able to see more operations.
javaserverfaces-spec-public

Relative Resources

Created: 09/Mar/11 02:04 PM   Updated: 08/Nov/13 09:15 PM
Component/s: Resources
Affects Version/s: 2.2
Fix Version/s: 2.3

Time Tracking:
Issue & Sub-Tasks
Issue Only
Original Estimate: 5 days
Original Estimate - 5 days
Remaining Estimate: 5 days
Time Spent - 2 hours Remaining Estimate - 5 days
Time Spent: 2 hours
Time Spent - 2 hours Remaining Estimate - 5 days

File Attachments: 1. Zip Archive sample.zip (14 kB) 27/Feb/12 09:48 PM - Ed Burns
2. Zip Archive sample_broken.zip (23 kB) 29/Feb/12 04:28 PM - Jakob Korherr

Issue Links:
Duplicate
 
Related
 

Status Whiteboard:

size_small importance_medium

Tags:
Participants: Ed Burns, Hanspeter Duennenberger, Jakob Korherr, lamine_ba and lu4242

  • Sub-Tasks:
  • All
  • Open

 Description  « Hide

https://issues.apache.org/jira/browse/MFCOMMONS-29

The features of this ResourceHandler include the following:

  • relative paths between resources (css files referencing images
    without using #resource['..'])
  • caching resources in the client (disabled if ProjectStage == Development)
  • GZIP compression and local cache in tmp dir (disabled if
    ProjectStage == Development)
  • i18n (supporting country code and language).

In addition, it does NOT support ValueExpressions in resource files
for performance reasons.

The most important feature, in my opinion, is how the resource URL is
built, e.g. /faces/javax.faces.resource/de_AT/$/some/library/$/my/resource.css

... because it permits resources referencing other resources without
#{resource['...']} (e.g. css files referencing images or other css
files). With the standard ResourceHandler this is 1) annoying if you
have to change the files you get from your designer and 2) a
performance bottleneck, because resources with ValueExpressions are
not cached and also regenerated for each request.

Furthermore, the resource URL contains the locale and thus you have no
problems with cached resources if a users changes the locale, because
he/she will get a new URL and thus a new resource (the right one).



Jakob Korherr added a comment - 15/Apr/11 04:18 AM

add duplicate links.


Jakob Korherr added a comment - 13/Jun/11 08:01 AM

Just found out that ICEFaces actually provides a tool for processing url() references in css files which are served by JSF 2.0. For example, this tool creates url(#{resource['org.site.lib/images/background.png']}) out of url(../images/background.png).

This shows the big impact of this issue, I think.

See http://wiki.icefaces.org/display/ICE/ACE+CSS+URL+Mapping for more details!

We seriously need to fix this with JSF 2.2! Such (annoying) preprocessing should not be necessary.


Hanspeter Duennenberger added a comment - 26/Aug/11 03:53 PM

Hi Jakob,

it would be usefull if there was a way to specify resources depending on the active ProjectStage - e.g. for css and Javascript files, to allow using packaged resources normally but uncompressed css/javascript when ProjectStage is set to Development.

I was discussing this once with someone and we ended up in a possible solution for that to put additional includeProjectStage/excludeProjectStage condition attributes on @ResourceDependency annotation and probably also same attributes on outputStylesheet/outputScript tags.

Might be this ends up in an additional independent issue, but as you are going to work on ResourceHandling anyway I feel adding it here is ok.

regards
Hanspeter


lu4242 added a comment - 29/Aug/11 01:25 AM - edited

In MyFaces and Tomahawk a custom hack is used to check if the project stage is Development and if a resource under META-INF/internal-resources (or in tomahawk META-INF/uncompressed-js-resources), just take this instead the compressed version used in Production stage.

I believe that it could be more simple to assume a "mirror uncompressed" location, and in practice use some plugin to compress the resources, and add the logic on the default (or custom) ResourceHandler algorithm.

EB> This approach breaks down when there is not a 1:1 mapping between
EB> compressed and non-comporessed resources. For example, when you
EB> want all your JS in one compressed file at Production time, and want
EB> several smaller, non-compressed files, at Development time.


Jakob Korherr added a comment - 04/Sep/11 03:05 PM

Hi Hanspeter,

This is a very, very nice idea! I will prototype that in my relative-resource-handler at apache-extras (see http://code.google.com/a/apache-extras.org/p/relative-resource-handler/).

Also: Since I will have more time in the next two weeks, I really do hope to get some work done for the spec!

Regards,
Jakob


Hanspeter Duennenberger added a comment - 03/Oct/11 02:19 PM

Hi Jakob,

any progress here?

I wanted to add something about the ProjectStage dependent resources. There might be two options for it:

1. use a project stage dependent resource path in the jar (similar to Locale handling with fallback). This is useful if the resource is the same name but only compressed for production, e.g.

myJs/some.js
myJs/production/some.js             (compressed some.js)

2. because the JS files may get pretty big, we would like to use multiple JS files for development but combine/compress a number of such JS files to one for production. This means the number of resource dependencies change depending on project stage.

myJs/funct-a.js
myJs/funct-b.js
myJs/funct-c.js
myJs/{production/}funct-all.js      (compressed combination of funct-*.js files)

So for example, it should be possible to state one component needs funct-a.js and funct-b.js when in project stage Development and only funct-all.js when in project stage Production.

I think possibility 1 is a little closer to what Leonardo mentioned about the MyFaces specific hack.
I really would like to have a specified way to handle project-stage specific resources, this might need some discussion in expert group though.

Cheers
Hanspeter


Jakob Korherr added a comment - 06/Oct/11 08:20 PM

Hi Hanspeter,

Currently I am trying to convince a professor at Vienna university of technology to let me write about the relative resource handler for my bachelor thesis. If this will be accepted, I will have a lot more time for the resource handler.

The idea is really very, very great and I'd like to do some prototyping here. However, I don't know if we should really follow a convention-over-configuration approach. I am actually not sure if we can find a convention for the resource name that will fit in most scenarios. Maybe we need some configuration mechanism here...

Regards,
Jakob


Hanspeter Duennenberger added a comment - 09/Feb/12 08:16 PM - edited

Hi all.

For multiple skins or theme support it will be necessary that the resource path may contain an optional skin or theme-path part.

Skin-one
 /resources/skin-one/css/main.css

 Skin-two
 /resources/skin-two/css/main.css

The reference to this resource could be:

<h:outputStylesheet name="main.css" library="css" />

I have kind of such an implementation, but it is probably to much integrated with our Skin interface. It should be a more general solution.

Regards
Hanspeter


Jakob Korherr added a comment - 14/Feb/12 07:54 PM

Hi hanspeter,

You are totally right! In my resource handler I called it "support for multi-tenancy", however, this is not implemented yet.

Actually you need to add every information you need to determine the correct resource into the resource path, thus it somehow is a REST url. I also added a resource-version to the path in order to deal with resource-update-browser-cache problems.

Regards,
Jakob


Ed Burns added a comment - 27/Feb/12 09:48 PM

Jakob, can you please hack upon this sample war to make it show the problem? The current war does use relative resources, but the browser is able to resolve them. Can you make it so the browser cannot resolve them?


Jakob Korherr added a comment - 29/Feb/12 04:25 PM

Hi Ed,

Your sample is somehow funny. You use a css file in webapp/resources/library/style.css using relative paths like this: url(../../included.css) and url(../../expert-draft-bg.png). The two referenced resources, of course, are located two folders up in the directory tree (directly in webapp).

Now as it would seem to be logical that this works, it really is a coincidence. You see, style.css is loaded via the following url:

http://localhost:8080/faces/javax.faces.resource/style.css?ln=library

Thus, included.css and expert-draft-bg.png are loaded by the browser using the following urls:

http://localhost:8080/included.css
http://localhost:8080/expert-draft-bg.png

The 1st ".." removed "javax.faces.resource" and the 2nd ".." removed "faces" (however, you would actually think that the 1st ".." removes library and the 2nd ".." removes "resources"). This, of course, only works because tomcat (or any other servlet container) serves the two files directly, and it has nothing to do with the JSF resource handler (e.g. ValueExpressions won't work!).

Now, there are a number of possibilities to break the example:
1) use .jsf instead of /faces/ FacesServlet mapping
2) locate the two resources in the same folder as style.css (while removing the ".." sequences in style.css)
3) locate the two resources in the classpath (META-INF/resources)
...

I used the 2nd of the above options in my sample_broken.zip.

Here, style.css still gets loaded via:

http://localhost:8080/faces/javax.faces.resource/style.css?ln=library

But now the browser tries to locate included.css and expert-draft-bg.png using these urls:

http://localhost:8080/faces/javax.faces.resource/included.css
http://localhost:8080/faces/javax.faces.resource/expert-draft-bg.png

Which does NOT work, because the library request parameter is missing. My approach (http://code.google.com/a/apache-extras.org/p/relative-resource-handler/) creates an url in which the library is included in the url path, thus this will work.

If you have any further questions, please ask!

Regards,
Jakob


Jakob Korherr added a comment - 29/Feb/12 04:28 PM

Added sample_broken.zip


Ed Burns added a comment - 29/Feb/12 06:11 PM

Thanks for demonstrating to me exactly how this is broken.

Now I can proceed to better see how to fix it!


Ed Burns added a comment - 29/Feb/12 09:08 PM

Looking at your relative-resource handler, it is immediately apparent that the ability for the relative resources to even work is based on how you are encoding the library name differently from what is specified. As stated in the javadocs for RelativeResourceHandler, you have to use

META-INF/relative-resources.xml

to declare libraries and we can't accept that requirement in the spec. Also, the stated limitation of only being able to work with prefix mapped JSF runtimes is unacceptable.

I can see why you made these decisions and how they enable the nice features of your Relative ResourceHandler, but we need to figure out how to do what you request without making unacceptable compromises.


Ed Burns added a comment - 29/Feb/12 09:14 PM

Jakob, what is the main reason for being dissatisfied with this syntax for relative resources?

css_master.css:

@import url(#{resource['this:layout.css']});

Is it performance?


Jakob Korherr added a comment - 29/Feb/12 11:59 PM

The need to have the libraryName configured in relative-resources.xml does only exist, because I needed a way to enable the RelativeResourceHandler only for certain libraries. This would not be necessary if the standard ResourceHandler already uses the "relative-mechanism" (for all libraries).

There are many reasons:

1) Acceptance: There is no other framework (at least which I know of), in which you cannot use relative paths between resources as they would work in the file system. Nearly every IDE supports "resource-exists-checks" in css files with relative paths in the file system, and these IDEs will mark #{resource[]} url references as errors. Every server (http or servlet container), CDN,... supports relative paths in the URLs like a normal file system, why should JSF do this differently?

2) Effort: You need quite a lot of time to change a big CSS framework (which you will get from your designers) into a working JSF version. And remember, next day the designer may change something, then you will get a new version of the whole CSS framework, and the work starts again...

3) Performance: Actually, having ValueExpressions in resource files is not only a performance killer, it also gives the developer the impression as if she could change resource file contents in every request, whereas she really cannot, because the resource will get cached by the browser/proxy.

I actually would not use the current JSF ResourceHandler because of these points and instead let tomcat (or even weblets) handle my resources, because they both support relative paths like a calm.


Ed Burns added a comment - 20/Mar/12 08:20 PM - edited

A resource path from Jakob's impl looks like
"/javax.faces.resource/1.0.0/en_US/css/style.css". Does that 1.0.0
refer to library version or resource version?

Here's a clue, from RelativeResourceHandler#132.

// skip version in url (first part, only there to avoid cache problems on updates)
final int versionSlash = resourceName.indexOf('/');

But that still doesn't answer my question. What does the 1.0.0 mean?

Jakob's ResourceHandler.createResource() allows the entire resourceId to
be in the "resourceName", which it re-interprets according to its own
rules if it determines that the library is not a JSF 2.0 style resource
library.

JK> The need to have the libraryName configured in
JK> relative-resources.xml does only exist, because I needed a way to
JK> enable the RelativeResourceHandler only for certain libraries. This
JK> would not be necessary if the standard ResourceHandler already uses
JK> the "relative-mechanism" (for all libraries).

Ok, let's say we make relative libraries the default for prefix mapped
applications. If we have a jar in the classpath that contains a library
that is arranged according to the JSF 2.0 spec for resource libraries,
we now we need some way to detect that case and use the JSF 2.0 style
arrangement, right?


lamine_ba added a comment - 21/Mar/12 01:13 PM - edited

For what it's worth, JSF 2.0 has already a support for Relative Resources but only if you use a prefix mapping in your application. There is a bug in the implementations and it is in how they are interpreting the information in order to create the resource. you can solve this problem by wrapping the default ResourceHandler to correct the mistake in the createResource method. If I put this into practice and reuse the sample war, I will first correct the example by respecting the structure of a resource library. So Here is how things should be laid on.

Structure

  • resources
    • css
      • style.css
      • included.css
    • images
      • header.png
      • expert-draft-bg.png

Now Let's use the style in our Facelets Page

<h:outputStylesheet name="style.css" library="css" />

The generated URL will be : http://localhost:8080/faces/javax.faces.resource/style.css?ln=css.

and the browser will after use http://localhost:8080/faces/javax.faces.resource/ to load the other resources referenced in this css file. So to have them correctly loaded here is how you should reference them

-style.css : First Version

@import url(included.css?ln=css);
body{
  background-image:url(expert-draft-bg.png?ln=images);
}
div#header{
  background-image:url(header.png?ln=images);
}

-style.css : Second Version

@import url(css/included.css);
body{
  background-image:url(images/expert-draft-bg.png);
}
div#header{
  background-image:url(images/header.png);
}

In this last variation, the one I currently use in my application, The ResourceHandler must be intelligent enough to know that the libraryName will be null and that its value will be inside the resource name ( images/expert-draft-bg.png, css/included.css).