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    }