001 // Copyright 2006, 2007, 2008, 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.Asset;
018 import org.apache.tapestry5.ioc.Resource;
019 import org.apache.tapestry5.ioc.annotations.Marker;
020 import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
021 import org.apache.tapestry5.services.AssetFactory;
022 import org.apache.tapestry5.services.AssetPathConverter;
023 import org.apache.tapestry5.services.ClasspathAssetAliasManager;
024 import org.apache.tapestry5.services.ClasspathProvider;
025
026 /**
027 * Generates Assets for files on the classpath. Caches generated client URLs internally, and clears that cache when
028 * notified to do so by the {@link ResourceDigestManager}.
029 *
030 * @see AssetDispatcher
031 */
032 @Marker(ClasspathProvider.class)
033 public class ClasspathAssetFactory implements AssetFactory
034 {
035 private final ResourceDigestManager digestManager;
036
037 private final ClasspathAssetAliasManager aliasManager;
038
039 private final ClasspathResource rootResource;
040
041 private final AssetPathConverter converter;
042
043 private final boolean invariant;
044
045 public ClasspathAssetFactory(ResourceDigestManager digestManager, ClasspathAssetAliasManager aliasManager,
046 AssetPathConverter converter)
047 {
048 this.digestManager = digestManager;
049 this.aliasManager = aliasManager;
050 this.converter = converter;
051
052 rootResource = new ClasspathResource("");
053
054 invariant = converter.isInvariant();
055 }
056
057 private String clientURL(Resource resource)
058 {
059 String defaultPath = buildDefaultPath(resource);
060
061 return converter.convertAssetPath(defaultPath);
062 }
063
064 private String buildDefaultPath(Resource resource)
065 {
066 boolean requiresDigest = digestManager.requiresDigest(resource);
067
068 String path = resource.getPath();
069
070 if (requiresDigest)
071 {
072 // Resources with extensions go from foo/bar/baz.txt --> foo/bar/baz.CHECKSUM.txt
073
074 int lastdotx = path.lastIndexOf('.');
075
076 path = path.substring(0, lastdotx + 1) + digestManager.getDigest(resource) + path.substring(lastdotx);
077 }
078
079 return aliasManager.toClientURL(path);
080 }
081
082 public Asset createAsset(Resource resource)
083 {
084 if (invariant)
085 {
086 return createInvariantAsset(resource);
087 }
088
089 return createVariantAsset(resource);
090 }
091
092 /**
093 * A variant asset must pass the resource through clientURL() all the time; very inefficient.
094 */
095 private Asset createVariantAsset(final Resource resource)
096 {
097 return new AbstractAsset(false)
098 {
099 public Resource getResource()
100 {
101 return resource;
102 }
103
104 public String toClientURL()
105 {
106 return clientURL(resource);
107 }
108 };
109 }
110
111 /**
112 * An invariant asset is normal, and only needs to compute the clientURL for the resource once.
113 */
114 private Asset createInvariantAsset(final Resource resource)
115 {
116 return new AbstractAsset(true)
117 {
118 private String clientURL;
119
120 public Resource getResource()
121 {
122 return resource;
123 }
124
125 public String toClientURL()
126 {
127 if (clientURL == null)
128 {
129 clientURL = clientURL(resource);
130 }
131
132 return clientURL;
133 }
134 };
135 }
136
137 public Resource getRootResource()
138 {
139 return rootResource;
140 }
141 }