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