    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    }