1 15 package org.apache.tapestry.asset; 16 17 import java.io.BufferedInputStream ; 18 import java.io.IOException ; 19 import java.io.InputStream ; 20 import java.io.OutputStream ; 21 import java.net.URL ; 22 import java.net.URLConnection ; 23 import java.util.HashMap ; 24 import java.util.Map ; 25 26 import javax.servlet.http.HttpServletResponse ; 27 28 import org.apache.hivemind.ApplicationRuntimeException; 29 import org.apache.hivemind.ClassResolver; 30 import org.apache.hivemind.util.Defense; 31 import org.apache.hivemind.util.IOUtils; 32 import org.apache.tapestry.IRequestCycle; 33 import org.apache.tapestry.Tapestry; 34 import org.apache.tapestry.engine.IEngineService; 35 import org.apache.tapestry.engine.ILink; 36 import org.apache.tapestry.error.RequestExceptionReporter; 37 import org.apache.tapestry.link.StaticLink; 38 import org.apache.tapestry.services.LinkFactory; 39 import org.apache.tapestry.services.ServiceConstants; 40 import org.apache.tapestry.util.ContentType; 41 import org.apache.tapestry.web.WebContext; 42 import org.apache.tapestry.web.WebRequest; 43 import org.apache.tapestry.web.WebResponse; 44 45 58 59 public class AssetService implements IEngineService 60 { 61 62 63 private ClassResolver _classResolver; 64 65 66 private AssetExternalizer _assetExternalizer; 67 68 69 private LinkFactory _linkFactory; 70 71 72 private WebContext _context; 73 74 75 76 private WebRequest _request; 77 78 79 private WebResponse _response; 80 81 82 private ResourceDigestSource _digestSource; 83 84 88 89 private final static Map _mimeTypes; 90 91 static 92 { 93 _mimeTypes = new HashMap (17); 94 _mimeTypes.put("css", "text/css"); 95 _mimeTypes.put("gif", "image/gif"); 96 _mimeTypes.put("jpg", "image/jpeg"); 97 _mimeTypes.put("jpeg", "image/jpeg"); 98 _mimeTypes.put("htm", "text/html"); 99 _mimeTypes.put("html", "text/html"); 100 } 101 102 private static final int BUFFER_SIZE = 10240; 103 104 109 110 private final long _startupTime = System.currentTimeMillis(); 111 112 116 117 private final long _expireTime = _startupTime + 365 * 24 * 60 * 60 * 1000; 118 119 120 121 private RequestExceptionReporter _exceptionReporter; 122 123 128 129 public static final String PATH = "path"; 130 131 137 138 public static final String DIGEST = "digest"; 139 140 146 147 public ILink getLink(IRequestCycle cycle, Object parameter) 148 { 149 Defense.isAssignable(parameter, String .class, "parameter"); 150 151 String path = (String ) parameter; 152 153 String externalURL = _assetExternalizer.getURL(path); 154 155 if (externalURL != null) 156 return new StaticLink(externalURL); 157 158 String digest = _digestSource.getDigestForResource(path); 159 160 Map parameters = new HashMap (); 161 162 parameters.put(ServiceConstants.SERVICE, Tapestry.ASSET_SERVICE); 163 parameters.put(PATH, path); 164 parameters.put(DIGEST, digest); 165 166 168 return _linkFactory.constructLink(cycle, parameters, false); 169 } 170 171 public String getName() 172 { 173 return Tapestry.ASSET_SERVICE; 174 } 175 176 private String getMimeType(String path) 177 { 178 String result = _context.getMimeType(path); 179 180 if (result == null) 181 { 182 int dotx = path.lastIndexOf('.'); 183 String key = path.substring(dotx + 1).toLowerCase(); 184 185 result = (String ) _mimeTypes.get(key); 186 187 if (result == null) 188 result = "text/plain"; 189 } 190 191 return result; 192 } 193 194 200 201 public void service(IRequestCycle cycle) throws IOException 202 { 203 206 if (_request.getHeader("If-Modified-Since") != null) 207 { 208 _response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); 209 return; 210 } 211 212 String path = cycle.getParameter(PATH); 213 String md5 = cycle.getParameter(DIGEST); 214 215 try 216 { 217 if (!_digestSource.getDigestForResource(path).equals(md5)) 218 throw new ApplicationRuntimeException(AssetMessages.md5Mismatch(path)); 219 220 URL resourceURL = _classResolver.getResource(path); 221 222 if (resourceURL == null) 223 throw new ApplicationRuntimeException(AssetMessages.noSuchResource(path)); 224 225 URLConnection resourceConnection = resourceURL.openConnection(); 226 227 writeAssetContent(cycle, path, resourceConnection); 228 } 229 catch (Throwable ex) 230 { 231 _exceptionReporter.reportRequestException(AssetMessages.exceptionReportTitle(path), ex); 232 } 233 234 } 235 236 237 238 private void writeAssetContent(IRequestCycle cycle, String resourcePath, 239 URLConnection resourceConnection) throws IOException 240 { 241 InputStream input = null; 242 243 try 244 { 245 249 String contentType = getMimeType(resourcePath); 250 int contentLength = resourceConnection.getContentLength(); 251 252 if (contentLength > 0) 253 _response.setContentLength(contentLength); 254 255 _response.setDateHeader("Last-Modified", _startupTime); 256 _response.setDateHeader("Expires", _expireTime); 257 258 261 if (contentType == null || contentType.length() == 0) 262 contentType = getMimeType(resourcePath); 263 264 OutputStream output = _response.getOutputStream(new ContentType(contentType)); 265 266 input = new BufferedInputStream (resourceConnection.getInputStream()); 267 268 byte[] buffer = new byte[BUFFER_SIZE]; 269 270 while (true) 271 { 272 int bytesRead = input.read(buffer); 273 274 if (bytesRead < 0) 275 break; 276 277 output.write(buffer, 0, bytesRead); 278 } 279 280 input.close(); 281 input = null; 282 } 283 finally 284 { 285 IOUtils.close(input); 286 } 287 } 288 289 290 291 public void setExceptionReporter(RequestExceptionReporter exceptionReporter) 292 { 293 _exceptionReporter = exceptionReporter; 294 } 295 296 297 public void setAssetExternalizer(AssetExternalizer assetExternalizer) 298 { 299 _assetExternalizer = assetExternalizer; 300 } 301 302 303 public void setLinkFactory(LinkFactory linkFactory) 304 { 305 _linkFactory = linkFactory; 306 } 307 308 309 public void setClassResolver(ClassResolver classResolver) 310 { 311 _classResolver = classResolver; 312 } 313 314 315 public void setContext(WebContext context) 316 { 317 _context = context; 318 } 319 320 321 public void setResponse(WebResponse response) 322 { 323 _response = response; 324 } 325 326 327 public void setDigestSource(ResourceDigestSource md5Source) 328 { 329 _digestSource = md5Source; 330 } 331 332 333 public void setRequest(WebRequest request) 334 { 335 _request = request; 336 } 337 } | Popular Tags |