Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Critical Critical
    • Resolution: Unresolved
    • Affects Version/s: 2.2
    • Fix Version/s: None
    • Component/s: Resources
    • Labels:
      None
    • Status Whiteboard:
      Hide

      size_small importance_medium

      Show
      size_small importance_medium

      Description

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

        Issue Links

          Activity

          Ed Burns created issue -
          Jakob Korherr made changes -
          Field Original Value New Value
          Link This issue is duplicated by JAVASERVERFACES_SPEC_PUBLIC-884 [ JAVASERVERFACES_SPEC_PUBLIC-884 ]
          Hide
          Jakob Korherr added a comment -

          add duplicate links.

          Show
          Jakob Korherr added a comment - add duplicate links.
          Jakob Korherr made changes -
          Hide
          Jakob Korherr added a comment -

          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.

          Show
          Jakob Korherr added a comment - 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.
          Ed Burns made changes -
          Original Estimate 5 days [ 432000 ]
          Remaining Estimate 5 days [ 432000 ]
          Hide
          Hanspeter Duennenberger added a comment -

          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

          Show
          Hanspeter Duennenberger added a comment - 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
          Hide
          lu4242 added a comment - - 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.

          Show
          lu4242 added a comment - - 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.
          Hide
          Jakob Korherr added a comment -

          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

          Show
          Jakob Korherr added a comment - 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
          Hide
          Hanspeter Duennenberger added a comment -

          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

          Show
          Hanspeter Duennenberger added a comment - 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
          Hide
          Jakob Korherr added a comment -

          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

          Show
          Jakob Korherr added a comment - 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
          Ed Burns made changes -
          Affects Version/s 2.2 [ 10403 ]
          Hide
          Hanspeter Duennenberger added a comment - - 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

          Show
          Hanspeter Duennenberger added a comment - - 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
          Hide
          Jakob Korherr added a comment -

          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

          Show
          Jakob Korherr added a comment - 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
          Hide
          Ed Burns added a comment -

          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?

          Show
          Ed Burns added a comment - 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?
          Ed Burns made changes -
          Attachment sample.zip [ 49420 ]
          Ed Burns made changes -
          Hide
          Jakob Korherr added a comment -

          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

          Show
          Jakob Korherr added a comment - 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
          Hide
          Jakob Korherr added a comment -

          Added sample_broken.zip

          Show
          Jakob Korherr added a comment - Added sample_broken.zip
          Jakob Korherr made changes -
          Attachment sample_broken.zip [ 49428 ]
          Hide
          Ed Burns added a comment -

          Thanks for demonstrating to me exactly how this is broken.

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

          Show
          Ed Burns added a comment - Thanks for demonstrating to me exactly how this is broken. Now I can proceed to better see how to fix it!
          Hide
          Ed Burns added a comment -

          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.

          Show
          Ed Burns added a comment - 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.
          Hide
          Ed Burns added a comment -

          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?

          Show
          Ed Burns added a comment - 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?
          Hide
          Jakob Korherr added a comment -

          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.

          Show
          Jakob Korherr added a comment - 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.
          Hide
          Ed Burns added a comment - - 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?

          Show
          Ed Burns added a comment - - 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?
          Ed Burns made changes -
          Link This issue is duplicated by JAVASERVERFACES-1189 [ JAVASERVERFACES-1189 ]
          Ed Burns made changes -
          Fix Version/s 2.2 [ 10403 ]
          Ed Burns made changes -
          Fix Version/s 2.3 [ 16372 ]
          Fix Version/s 2.2 [ 10403 ]
          Ed Burns made changes -
          Assignee Ed Burns [ edburns ]
          Hide
          Ed Burns added a comment -

          Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.

          Show
          Ed Burns added a comment - Set priority to baseline ahead of JSF 2.3 triage. Priorities will be assigned accurately after this exercise.
          Ed Burns made changes -
          Priority Minor [ 4 ] Trivial [ 5 ]
          Fix Version/s 2.3 [ 16372 ]
          Manfred Riem made changes -
          Priority Trivial [ 5 ] Critical [ 2 ]
          Hide
          Manfred Riem added a comment -

          Setting priority to Critical

          Show
          Manfred Riem added a comment - Setting priority to Critical
          lamine_ba made changes -
          Comment [ 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
          {code}
          @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);
          }
          {code}
          -style.css : Second Version

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

          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).
          ]

            People

            • Assignee:
              Unassigned
              Reporter:
              Ed Burns
            • Votes:
              24 Vote for this issue
              Watchers:
              7 Start watching this issue

              Dates

              • Created:
                Updated:

                Time Tracking

                Estimated:
                Original Estimate - 5 days Original Estimate - 5 days
                5d
                Remaining:
                Time Spent - 2 hours Remaining Estimate - 5 days
                5d
                Logged:
                Time Spent - 2 hours Remaining Estimate - 5 days
                2h