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 }