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 }