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 }