Author: hlship
Date: Mon Apr 19 13:24:32 2010
New Revision: 935556

URL: http://svn.apache.org/viewvc?rev=935556&view=rev
Log:
Rework ClasspathAssetAliasManager to always require a mapping to an aliased 
package folder

Modified:
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
    
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
    
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java?rev=935556&r1=935555&r2=935556&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
 Mon Apr 19 13:24:32 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,7 +14,12 @@
 
 package org.apache.tapestry5.internal.services;
 
+import org.apache.tapestry5.SymbolConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.util.AvailableValues;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
 import org.apache.tapestry5.services.ClasspathAssetAliasManager;
 import org.apache.tapestry5.services.Request;
 
@@ -27,6 +32,8 @@ public class ClasspathAssetAliasManagerI
 {
     private final Request request;
 
+    private final String assetPathPrefix;
+
     /**
      * Map from alias to path.
      */
@@ -44,17 +51,26 @@ public class ClasspathAssetAliasManagerI
     /**
      * Configuration is a map of aliases (short names) to complete names. Keys 
and values should end with a slash, but
      * one will be provided as necessary, so don't both.
+     * 
+     * @param applicationVersion
+     *            TODO
      */
     public ClasspathAssetAliasManagerImpl(Request request,
 
-                                          Map<String, String> configuration)
+    @Inject
+    @Symbol(SymbolConstants.APPLICATION_VERSION)
+    String applicationVersion,
+
+    Map<String, String> configuration)
     {
         this.request = request;
 
+        this.assetPathPrefix = RequestConstants.ASSET_PATH_PREFIX + 
applicationVersion + "/";
+
         for (Map.Entry<String, String> e : configuration.entrySet())
         {
-            String alias = withSlash(e.getKey());
-            String path = withSlash(e.getValue());
+            String alias = withOutSlash(e.getKey());
+            String path = withOutSlash(e.getValue());
 
             aliasToPathPrefix.put(alias, path);
             pathPrefixToAlias.put(path, alias);
@@ -76,19 +92,18 @@ public class ClasspathAssetAliasManagerI
         Collections.sort(sortedPathPrefixes, sortDescendingByLength);
     }
 
-    private String withSlash(String input)
+    private String withOutSlash(String input)
     {
-        if (input.equals("")) return input;
-
-        if (input.endsWith("/")) return input;
+        if (input.endsWith("/"))
+            return input.substring(0, input.length() - 1);
 
-        return input + "/";
+        return input;
     }
 
     public String toClientURL(String resourcePath)
     {
         StringBuilder builder = new StringBuilder(request.getContextPath());
-        builder.append(RequestConstants.ASSET_PATH_PREFIX);
+        builder.append(assetPathPrefix);
 
         for (String pathPrefix : sortedPathPrefixes)
         {
@@ -96,29 +111,32 @@ public class ClasspathAssetAliasManagerI
             {
                 String alias = pathPrefixToAlias.get(pathPrefix);
                 builder.append(alias);
-                builder.append(resourcePath.substring(pathPrefix.length()));
+                builder.append("/");
+                builder.append(resourcePath.substring(pathPrefix.length() + 
1));
 
                 return builder.toString();
             }
         }
 
-        // No alias available as a prefix (kind of unlikely, but whatever).
+        // This is a minor misuse of the UnknownValueException but the 
exception reporting
+        // is too useful to pass up.
 
-        builder.append(resourcePath);
-
-        return builder.toString();
+        throw new UnknownValueException(
+                String
+                        .format(
+                                "Unable to create a client URL for classpath 
resource %s: The resource path was not within an aliased path.",
+                                resourcePath), new AvailableValues("aliased 
paths", aliasToPathPrefix.values()));
     }
 
     public String toResourcePath(String clientURL)
     {
+        // Include the slash in the base path
+
         String basePath = 
clientURL.substring(RequestConstants.ASSET_PATH_PREFIX.length());
 
         for (String alias : sortedAliases)
         {
-            if (basePath.startsWith(alias))
-            {
-                return aliasToPathPrefix.get(alias) + 
basePath.substring(alias.length());
-            }
+            if (basePath.startsWith(alias)) { return 
aliasToPathPrefix.get(alias) + "/" + basePath.substring(alias.length() + 1); }
         }
 
         return basePath;

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java?rev=935556&r1=935555&r2=935556&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
 Mon Apr 19 13:24:32 2010
@@ -1,10 +1,10 @@
-// Copyright 2006, 2008 The Apache Software Foundation
+// Copyright 2006, 2008, 2010 The Apache Software Foundation
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,12 +17,23 @@ package org.apache.tapestry5.services;
 import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
 
 /**
- * Used as part of the support for classpath {...@link 
org.apache.tapestry5.Asset}s, to convert the Asset's {...@link
- * org.apache.tapestry5.ioc.Resource} to a URL that can be accessed by the 
client.    The asset path, within the
+ * Used as part of the support for classpath {...@link 
org.apache.tapestry5.Asset}s, to convert the Asset's
+ * {...@link org.apache.tapestry5.ioc.Resource} to a URL that can be accessed 
by the client. The asset path, within the
  * classpath, is converted into a shorter virtual path (one that, typically, 
includes some kind of version number).
  * <p/>
  * Service configuration is a map from aliases (short names) to complete 
names. Names should not start or end end with a
- * slash.
+ * slash. Generally, an alias should be a single name (not contain a slash). 
Paths should also not start or end with a
+ * slash. An example mapping would be <code>mylib</code> to 
<code>com/example/mylib</code>.
+ * <p>
+ * As originally envisioned, this service would simply <em>optimize</em> 
classpath assets, allowing the URL path for
+ * such assets to be shortened (and have a version number added, important for 
caching); thus the word "alias" makes
+ * sense ... it was responsible for creating an "alias" URL shorter than the 
default "classpath" URL.
+ * <p>
+ * Starting in Tapestry 5.2, this changed; all classpath assets 
<strong>must</strong> be "aliased" to a shorter URL
+ * path. Any URL that can not be shortened is now rejected.
+ * <p>
+ * Tapestry automatically contributes a number of mappings: for the 
application itself (as alias "app") and for each
+ * library (via {...@link ComponentClassResolver#getFolderToPackageMapping()});
  */
 @UsesMappedConfiguration(String.class)
 public interface ClasspathAssetAliasManager
@@ -30,8 +41,9 @@ public interface ClasspathAssetAliasMana
     /**
      * Takes a resource path to a classpath resource and adds the asset path 
prefix to the path. May also convert part
      * of the path to an alias (based on the manager's configuration).
-     *
-     * @param resourcePath resource path on the classpath (with no leading 
slash)
+     * 
+     * @param resourcePath
+     *            resource path on the classpath (with no leading slash)
      * @return URL ready to send to the client
      */
     String toClientURL(String resourcePath);

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java?rev=935556&r1=935555&r2=935556&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/ComponentClassResolver.java
 Mon Apr 19 13:24:32 2010
@@ -119,6 +119,7 @@ public interface ComponentClassResolver
      * folder "example", then the package mapping for "example" will be 
<code>com.example</code>.
      * 
      * @since 5.2.0
+     * @see ClasspathAssetAliasManager
      */
     Map<String, String> getFolderToPackageMapping();
 }

Modified: 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java?rev=935556&r1=935555&r2=935556&view=diff
==============================================================================
--- 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
 (original)
+++ 
tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
 Mon Apr 19 13:24:32 2010
@@ -4,7 +4,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+// http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,6 +15,8 @@
 package org.apache.tapestry5.internal.services;
 
 import org.apache.tapestry5.internal.test.InternalBaseTestCase;
+import org.apache.tapestry5.ioc.util.UnknownValueException;
+
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import org.apache.tapestry5.services.ClasspathAssetAliasManager;
 import org.apache.tapestry5.services.Request;
@@ -25,6 +27,7 @@ import java.util.Map;
 
 public class ClasspathAssetAliasManagerImplTest extends InternalBaseTestCase
 {
+    private static final String APP_VERSION = "1.2.3";
 
     public Map<String, String> configuration()
     {
@@ -33,7 +36,6 @@ public class ClasspathAssetAliasManagerI
         configuration.put("tapestry/4.0", "org/apache/tapestry5/");
         configuration.put("tapestry-internal/3.0", 
"org/apache/tapestry5/internal/");
         configuration.put("mylib/2.0/", "com/example/mylib/");
-        configuration.put("classpath/1.0", "");
 
         return configuration;
     }
@@ -47,10 +49,38 @@ public class ClasspathAssetAliasManagerI
 
         replay();
 
-        ClasspathAssetAliasManager manager = new 
ClasspathAssetAliasManagerImpl(request, configuration());
+        ClasspathAssetAliasManager manager = new 
ClasspathAssetAliasManagerImpl(request, APP_VERSION, configuration());
+
+        String expectedPath = "/ctx" + RequestConstants.ASSET_PATH_PREFIX + 
APP_VERSION + "/" + expectedClientURL;
 
-        assertEquals(manager.toClientURL(resourcePath),
-                     "/ctx" + RequestConstants.ASSET_PATH_PREFIX + 
expectedClientURL);
+        assertEquals(manager.toClientURL(resourcePath), expectedPath);
+
+        verify();
+    }
+
+    @Test
+    public void failure_if_path_not_in_mapped_alias_folder()
+    {
+        Request request = mockRequest();
+
+        train_getContextPath(request, "");
+
+        replay();
+
+        ClasspathAssetAliasManager manager = new 
ClasspathAssetAliasManagerImpl(request, APP_VERSION, configuration());
+
+        try
+        {
+            manager.toClientURL("org/example/icons/flag.gif");
+            unreachable();
+        }
+        catch (UnknownValueException ex)
+        {
+            assertMessageContains(ex, "Unable to create a client URL for 
classpath resource org/example/icons/flag.gif");
+
+            assertListsEquals(ex.getAvailableValues().getValues(), 
"com/example/mylib", "org/apache/tapestry5",
+                    "org/apache/tapestry5/internal");
+        }
 
         verify();
     }
@@ -58,17 +88,18 @@ public class ClasspathAssetAliasManagerI
     @DataProvider
     public Object[][] to_client_url_data()
     {
-        return new Object[][] { { "foo/bar/Baz.txt", 
"classpath/1.0/foo/bar/Baz.txt" },
-                { "com/example/mylib/Foo.bar", "mylib/2.0/Foo.bar" },
-                { "com/example/mylib/nested/Foo.bar", 
"mylib/2.0/nested/Foo.bar" },
-                { "org/apache/tapestry5/internal/Foo.bar", 
"tapestry-internal/3.0/Foo.bar" },
-                { "org/apache/tapestry5/Foo.bar", "tapestry/4.0/Foo.bar" }, };
+        return new Object[][]
+        {
+        { "com/example/mylib/Foo.bar", "mylib/2.0/Foo.bar" },
+        { "com/example/mylib/nested/Foo.bar", "mylib/2.0/nested/Foo.bar" },
+        { "org/apache/tapestry5/internal/Foo.bar", 
"tapestry-internal/3.0/Foo.bar" },
+        { "org/apache/tapestry5/Foo.bar", "tapestry/4.0/Foo.bar" }, };
     }
 
     @Test(dataProvider = "to_resource_path_data")
     public void to_resource_path(String clientURL, String expectedResourcePath)
     {
-        ClasspathAssetAliasManager manager = new 
ClasspathAssetAliasManagerImpl(null, configuration());
+        ClasspathAssetAliasManager manager = new 
ClasspathAssetAliasManagerImpl(null, APP_VERSION, configuration());
 
         assertEquals(manager.toResourcePath(clientURL), expectedResourcePath);
     }


Reply via email to