001 // Copyright 2006, 2007, 2008, 2009, 2010 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.Asset; 018 import org.apache.tapestry5.internal.AssetConstants; 019 import org.apache.tapestry5.internal.TapestryInternalUtils; 020 import org.apache.tapestry5.ioc.Resource; 021 import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 022 import org.apache.tapestry5.ioc.internal.util.InternalUtils; 023 import org.apache.tapestry5.ioc.services.SymbolSource; 024 import org.apache.tapestry5.ioc.services.ThreadLocale; 025 import org.apache.tapestry5.ioc.util.StrategyRegistry; 026 import org.apache.tapestry5.services.AssetFactory; 027 import org.apache.tapestry5.services.AssetSource; 028 029 import java.lang.ref.SoftReference; 030 import java.util.Locale; 031 import java.util.Map; 032 033 @SuppressWarnings("all") 034 public class AssetSourceImpl implements AssetSource 035 { 036 private final StrategyRegistry<AssetFactory> registry; 037 038 private final ThreadLocale threadLocale; 039 040 private final Map<String, Resource> prefixToRootResource = CollectionFactory.newMap(); 041 042 private final Map<Resource, SoftReference<Asset>> cache = CollectionFactory.newWeakHashMap(); 043 044 private final SymbolSource symbolSource; 045 046 public AssetSourceImpl(ThreadLocale threadLocale, 047 048 Map<String, AssetFactory> configuration, SymbolSource symbolSource) 049 { 050 this.threadLocale = threadLocale; 051 this.symbolSource = symbolSource; 052 053 Map<Class, AssetFactory> byResourceClass = CollectionFactory.newMap(); 054 055 for (Map.Entry<String, AssetFactory> e : configuration.entrySet()) 056 { 057 String prefix = e.getKey(); 058 AssetFactory factory = e.getValue(); 059 060 Resource rootResource = factory.getRootResource(); 061 062 byResourceClass.put(rootResource.getClass(), factory); 063 064 prefixToRootResource.put(prefix, rootResource); 065 } 066 067 registry = StrategyRegistry.newInstance(AssetFactory.class, byResourceClass); 068 } 069 070 public Asset getClasspathAsset(String path) 071 { 072 return getClasspathAsset(path, null); 073 } 074 075 public Asset getClasspathAsset(String path, Locale locale) 076 { 077 return getAsset(null, path, locale); 078 } 079 080 public Asset getContextAsset(String path, Locale locale) 081 { 082 return getAsset(prefixToRootResource.get(AssetConstants.CONTEXT), path, locale); 083 } 084 085 public Asset getAsset(Resource baseResource, String path, Locale locale) 086 { 087 return getAssetInLocale(baseResource, path, defaulted(locale)); 088 } 089 090 public Resource resourceForPath(String path) 091 { 092 return getUnlocalizedResource(null, path); 093 } 094 095 public Asset getExpandedAsset(String path) 096 { 097 return getUnlocalizedAsset(symbolSource.expandSymbols(path)); 098 } 099 100 public Asset getUnlocalizedAsset(String path) 101 { 102 return getAssetInLocale(null, path, null); 103 } 104 105 private Asset getAssetInLocale(Resource baseResource, String path, Locale locale) 106 { 107 return getLocalizedAssetFromResource(getUnlocalizedResource(baseResource, path), locale); 108 } 109 110 private Resource getUnlocalizedResource(Resource baseResource, String path) 111 { 112 assert InternalUtils.isNonBlank(path); 113 int colonx = path.indexOf(':'); 114 115 if (colonx < 0) 116 { 117 Resource root = baseResource != null ? baseResource : prefixToRootResource.get(AssetConstants.CLASSPATH); 118 119 return root.forFile(path); 120 } 121 122 String prefix = path.substring(0, colonx); 123 124 Resource root = prefixToRootResource.get(prefix); 125 126 if (root == null) 127 throw new IllegalArgumentException(ServicesMessages.unknownAssetPrefix(path)); 128 129 return root.forFile(path.substring(colonx + 1)); 130 } 131 132 private Asset getLocalizedAssetFromResource(Resource unlocalized, Locale locale) 133 { 134 Resource localized = locale == null ? unlocalized : unlocalized.forLocale(locale); 135 136 if (localized == null || !localized.exists()) 137 throw new RuntimeException(ServicesMessages.assetDoesNotExist(unlocalized)); 138 139 return getAssetForResource(localized); 140 } 141 142 private synchronized Asset getAssetForResource(Resource resource) 143 { 144 Asset result = TapestryInternalUtils.getAndDeref(cache, resource); 145 146 if (result == null) 147 { 148 result = createAssetFromResource(resource); 149 cache.put(resource, new SoftReference(result)); 150 } 151 152 return result; 153 } 154 155 private Locale defaulted(Locale locale) 156 { 157 return locale != null ? locale : threadLocale.getLocale(); 158 } 159 160 private Asset createAssetFromResource(Resource resource) 161 { 162 // The class of the resource is derived from the class of the base resource. 163 // So we can then use the class of the resource as a key to locate the correct asset 164 // factory. 165 166 Class resourceClass = resource.getClass(); 167 168 AssetFactory factory = registry.get(resourceClass); 169 170 return factory.createAsset(resource); 171 } 172 }