Tapestry
  1. Tapestry
  2. TAPESTRY-1020

AssetService cannot handle relative paths when asset is in jar

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 4.1
    • Fix Version/s: 4.1
    • Component/s: Framework, JavaScript
    • Labels:
      None
    • Environment:
      Tapestry 4.1 head 21/7/06
      JBoss 4.0.4 GA

      Description

      Dojo uses relative paths to load modules. e.g. dojo/../tapestry/form.

      When these resources are stored within a jar, the Asset service cannot resolve them. I think it would work if they were part of the web resources (since that may use a file resolver) but the classpath resolver does not find them

      The AssetService needs to convert the supplied path to a cannonical form (no back references) before it tries to load the resource.

      I made a quick modification to the AssertService.translateCssPath method which accomplishes this.
      String translateCssPath(String path)
      {
      if (path == null) return null;

      // Remove back references in path.
      if( path.indexOf("/../") >= 0 ) {
      int start = path.indexOf("/../");
      while( start > 0 )

      { int parentStart = path.lastIndexOf("/", start-1); path = path.substring(0,parentStart+1) + path.substring(start+4); start = path.indexOf("/../"); }

      }

      // don't parse out actual css files
      if (path.endsWith(".css")) return path;

      int index = path.lastIndexOf(".css");
      if (index <= -1) return path;

      // now need to parse out whatever css file was referenced to get the real path
      int pathEnd = path.lastIndexOf("/", index);
      if (pathEnd <= -1) return path;

      return path.substring(0, pathEnd + 1) + path.substring(index + 4, path.length());
      }

      That passes these tests
      public void testRelativePaths()

      { AssetService service = new AssetService(); assertEquals("/src", service.translateCssPath("/dojo/../src")); assertEquals("src", service.translateCssPath("dojo/../src")); assertEquals("/src", service.translateCssPath("/dojo/blah/../../src")); assertEquals("src", service.translateCssPath("dojo/blah/../../src")); assertEquals("/src", service.translateCssPath("/dojo/../blah/../src")); assertEquals("src", service.translateCssPath("dojo/../blah/../src")); assertEquals("/src/", service.translateCssPath("/dojo/../src/")); assertEquals("src/", service.translateCssPath("dojo/../src/")); assertEquals("/", service.translateCssPath("/dojo/../")); assertEquals("", service.translateCssPath("dojo/../")); assertEquals("../dojo", service.translateCssPath("../dojo")); assertEquals("/../dojo", service.translateCssPath("/../dojo")); }
      1. TapBug.zip
        15 kB
        Ben Sommerville

        Activity

        Hide
        Jesse Kuhnert added a comment -

        Ok, fixed and re-deployed.

        Show
        Jesse Kuhnert added a comment - Ok, fixed and re-deployed.
        Hide
        Ben Sommerville added a comment -

        Thanks Jesse, that was quick!
        However I did find one small problem

        The commons-io normalization function converts the / chars to the system path separators. So on windows
        /dojo/dojo.js is converted to \\dojo
        dojo.js. Which is then not found by the class loader.

        You could run the output of FilenameUtils.normalize thru FilenameUtils.separatorsToUnix which should fix the problem (tho it starts to make the call a little ugly )

        Show
        Ben Sommerville added a comment - Thanks Jesse, that was quick! However I did find one small problem The commons-io normalization function converts the / chars to the system path separators. So on windows /dojo/dojo.js is converted to \\dojo dojo.js. Which is then not found by the class loader. You could run the output of FilenameUtils.normalize thru FilenameUtils.separatorsToUnix which should fix the problem (tho it starts to make the call a little ugly )
        Hide
        Jesse Kuhnert added a comment -

        Thanks a ton Ben! You are a lifesaver I was really getting worried about this one but couldn't make it happen in my own tap example app.

        I ended up using commons-io to normalize the filename path since it was already a Tapestry dependency. I'm deploying via maven as I write this comment so you should see it working in about 10 minutes or so.

        Show
        Jesse Kuhnert added a comment - Thanks a ton Ben! You are a lifesaver I was really getting worried about this one but couldn't make it happen in my own tap example app. I ended up using commons-io to normalize the filename path since it was already a Tapestry dependency. I'm deploying via maven as I write this comment so you should see it working in about 10 minutes or so.
        Hide
        Ben Sommerville added a comment -

        I've put together a small project which reproduces the problem for me.

        I built via maven & deployed manually into JBoss 4.0.4 GA.
        When I open the app the Login page gives the dojo errors.

        Show
        Ben Sommerville added a comment - I've put together a small project which reproduces the problem for me. I built via maven & deployed manually into JBoss 4.0.4 GA. When I open the app the Login page gives the dojo errors.
        Hide
        Ben Sommerville added a comment -

        The errors I get are:

        **********************************************************
        13:20:04,157 ERROR [STDERR] Failure to export classpath resource /dojo/_package_.js.
        13:20:04,157 ERROR [STDERR]Exceptions:
        13:20:04,173 ERROR [STDERR] org.apache.hivemind.ApplicationRuntimeException: Classpath resource '/dojo/_package_.js' does not exist.
        13:20:04,173 ERROR [STDERR] org.apache.tapestry.asset.AssetService.service(AssetService.java:247)

        **********************************************************
        13:20:04,267 ERROR [STDERR] Failure to export classpath resource /dojo/../tapestry/form.js.
        13:20:04,267 ERROR [STDERR] Exceptions:
        13:20:04,267 ERROR [STDERR] org.apache.hivemind.ApplicationRuntimeException: Classpath resource '/dojo/../tapestry/form.js' does not exist.

        On page I am viewing I get:
        FATAL: Could not load 'tapestry.html'; last tried '_package_.js'
        FATAL: Could not load 'tapestry.form'; last tried '_package_.js'

        Show
        Ben Sommerville added a comment - The errors I get are: ********************************************************** 13:20:04,157 ERROR [STDERR] Failure to export classpath resource /dojo/_ package _.js. 13:20:04,157 ERROR [STDERR] Exceptions: 13:20:04,173 ERROR [STDERR] org.apache.hivemind.ApplicationRuntimeException: Classpath resource '/dojo/_ package _.js' does not exist. 13:20:04,173 ERROR [STDERR] org.apache.tapestry.asset.AssetService.service(AssetService.java:247) ********************************************************** 13:20:04,267 ERROR [STDERR] Failure to export classpath resource /dojo/../tapestry/form.js. 13:20:04,267 ERROR [STDERR] Exceptions: 13:20:04,267 ERROR [STDERR] org.apache.hivemind.ApplicationRuntimeException: Classpath resource '/dojo/../tapestry/form.js' does not exist. On page I am viewing I get: FATAL: Could not load 'tapestry.html'; last tried '_ package _.js' FATAL: Could not load 'tapestry.form'; last tried '_ package _.js'
        Hide
        Jesse Kuhnert added a comment -

        Can you give me an example of a resource dojo has been unable to resolve when packaged into the Tapestry jar? I've not had this issue so far and would definitely like to investigate further.

        Show
        Jesse Kuhnert added a comment - Can you give me an example of a resource dojo has been unable to resolve when packaged into the Tapestry jar? I've not had this issue so far and would definitely like to investigate further.

          People

          • Assignee:
            Jesse Kuhnert
            Reporter:
            Ben Sommerville
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development