001 // Copyright 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.assets; 016 017 import org.apache.tapestry5.internal.TapestryInternalUtils; 018 import org.apache.tapestry5.ioc.Resource; 019 import org.apache.tapestry5.services.assets.*; 020 021 import java.io.ByteArrayOutputStream; 022 import java.io.IOException; 023 import java.io.InputStream; 024 import java.util.Map; 025 026 public class StreamableResourceSourceImpl implements StreamableResourceSource 027 { 028 private final Map<String, ResourceTransformer> configuration; 029 030 private final ContentTypeAnalyzer contentTypeAnalyzer; 031 032 private final CompressionAnalyzer compressionAnalyzer; 033 034 private final ResourceChangeTracker resourceChangeTracker; 035 036 public StreamableResourceSourceImpl(Map<String, ResourceTransformer> configuration, 037 ContentTypeAnalyzer contentTypeAnalyzer, CompressionAnalyzer compressionAnalyzer, 038 ResourceChangeTracker resourceChangeTracker) 039 { 040 this.configuration = configuration; 041 this.contentTypeAnalyzer = contentTypeAnalyzer; 042 this.compressionAnalyzer = compressionAnalyzer; 043 this.resourceChangeTracker = resourceChangeTracker; 044 } 045 046 public StreamableResource getStreamableResource(Resource baseResource, StreamableResourceProcessing processing, ResourceDependencies dependencies) 047 throws IOException 048 { 049 assert baseResource != null; 050 051 if (!baseResource.exists()) 052 { 053 throw new IOException(String.format("Resource %s does not exist.", baseResource)); 054 } 055 056 String fileSuffix = TapestryInternalUtils.toFileSuffix(baseResource.getFile()); 057 058 // Optionally, transform the resource. The main driver for this is to allow 059 // for libraries like LessJS (http://lesscss.org/) or 060 // http://jashkenas.github.com/coffee-script/ 061 ResourceTransformer rt = configuration.get(fileSuffix); 062 063 InputStream transformed = rt == null ? baseResource.openStream() : rt.transform(baseResource, dependencies); 064 065 assert transformed != null; 066 067 BytestreamCache bytestreamCache = readStream(transformed); 068 069 transformed.close(); 070 071 String contentType = contentTypeAnalyzer.getContentType(baseResource); 072 073 boolean compressable = compressionAnalyzer.isCompressable(contentType); 074 075 long lastModified = resourceChangeTracker.trackResource(baseResource); 076 077 return new StreamableResourceImpl(baseResource.toString(), contentType, compressable ? CompressionStatus.COMPRESSABLE 078 : CompressionStatus.NOT_COMPRESSABLE, lastModified, bytestreamCache); 079 } 080 081 private BytestreamCache readStream(InputStream stream) throws IOException 082 { 083 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 084 085 TapestryInternalUtils.copy(stream, bos); 086 087 stream.close(); 088 089 return new BytestreamCache(bos); 090 } 091 092 }