001 // Copyright 2006, 2007, 2009, 2011 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.internal.services;
016
017 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
018 import org.apache.tapestry5.ioc.util.AvailableValues;
019 import org.apache.tapestry5.ioc.util.UnknownValueException;
020 import org.apache.tapestry5.services.ClasspathAssetAliasManager;
021 import org.apache.tapestry5.services.assets.AssetPathConstructor;
022
023 import java.util.Collections;
024 import java.util.Comparator;
025 import java.util.List;
026 import java.util.Map;
027
028 public class ClasspathAssetAliasManagerImpl implements ClasspathAssetAliasManager
029 {
030 private final AssetPathConstructor assetPathConstructor;
031
032 /**
033 * Map from alias to path.
034 */
035 private final Map<String, String> aliasToPathPrefix = CollectionFactory.newMap();
036
037 /**
038 * Map from path to alias.
039 */
040 private final Map<String, String> pathPrefixToAlias = CollectionFactory.newMap();
041
042 private final List<String> sortedAliases;
043
044 private final List<String> sortedPathPrefixes;
045
046 /**
047 * Configuration is a map of aliases (short names) to complete names. Keys and values should end with a slash, but
048 * one will be provided as necessary, so don't both.
049 */
050 public ClasspathAssetAliasManagerImpl(AssetPathConstructor assetPathConstructor,
051
052 Map<String, String> configuration)
053 {
054 this.assetPathConstructor = assetPathConstructor;
055
056 for (Map.Entry<String, String> e : configuration.entrySet())
057 {
058 String alias = verify("folder name", e.getKey());
059
060
061 String path = verify("path", e.getValue());
062
063 aliasToPathPrefix.put(alias, path);
064 pathPrefixToAlias.put(path, alias);
065 }
066
067 Comparator<String> sortDescendingByLength = new Comparator<String>()
068 {
069 public int compare(String o1, String o2)
070 {
071 return o2.length() - o1.length();
072 }
073 };
074
075 sortedAliases = CollectionFactory.newList(aliasToPathPrefix.keySet());
076 Collections.sort(sortedAliases, sortDescendingByLength);
077
078 sortedPathPrefixes = CollectionFactory.newList(aliasToPathPrefix.values());
079 Collections.sort(sortedPathPrefixes, sortDescendingByLength);
080 }
081
082 private String verify(String name, String input)
083 {
084
085 if (input.startsWith("/") || input.endsWith("/"))
086 throw new RuntimeException(String.format("Contribution of %s '%s' is invalid as it may not start with or end with a slash.",
087 name, input));
088
089 return input;
090
091 }
092
093 public String toClientURL(String resourcePath)
094 {
095 for (String pathPrefix : sortedPathPrefixes)
096 {
097 if (resourcePath.startsWith(pathPrefix))
098 {
099 String virtualFolder = pathPrefixToAlias.get(pathPrefix);
100
101 String virtualPath = resourcePath.substring(pathPrefix.length() + 1);
102
103 return assetPathConstructor.constructAssetPath(virtualFolder, virtualPath);
104 }
105 }
106
107 // This is a minor misuse of the UnknownValueException but the exception reporting
108 // is too useful to pass up.
109
110 throw new UnknownValueException(
111 String.format(
112 "Unable to create a client URL for classpath resource %s: The resource path was not within an aliased path.",
113 resourcePath), new AvailableValues("Aliased paths", aliasToPathPrefix.values()));
114 }
115
116 public Map<String, String> getMappings()
117 {
118 return Collections.unmodifiableMap(aliasToPathPrefix);
119 }
120
121 }