001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005// http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.internal.services.assets;
014
015import org.apache.tapestry5.http.ContentType;
016import org.apache.tapestry5.http.services.Response;
017import org.apache.tapestry5.services.assets.AssetChecksumGenerator;
018import org.apache.tapestry5.services.assets.CompressionStatus;
019import org.apache.tapestry5.services.assets.ResponseCustomizer;
020import org.apache.tapestry5.services.assets.StreamableResource;
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025
026public class StreamableResourceImpl implements StreamableResource
027{
028    protected final String description;
029
030    private final ContentType contentType;
031
032    protected final CompressionStatus compression;
033
034    protected final long lastModified;
035
036    protected final BytestreamCache bytestreamCache;
037
038    protected final AssetChecksumGenerator assetChecksumGenerator;
039
040    protected final ResponseCustomizer responseCustomizer;
041
042    public StreamableResourceImpl(String description, ContentType contentType, CompressionStatus compression, long lastModified, BytestreamCache bytestreamCache, AssetChecksumGenerator assetChecksumGenerator, ResponseCustomizer responseCustomizer)
043    {
044        this.lastModified = lastModified;
045        this.description = description;
046        this.bytestreamCache = bytestreamCache;
047        this.contentType = contentType;
048        this.compression = compression;
049        this.assetChecksumGenerator = assetChecksumGenerator;
050        this.responseCustomizer = responseCustomizer;
051    }
052
053    public String getDescription()
054    {
055        return description;
056    }
057
058    public CompressionStatus getCompression()
059    {
060        return compression;
061    }
062
063    public ContentType getContentType()
064    {
065        return contentType;
066    }
067
068    public int getSize()
069    {
070        return bytestreamCache.size();
071    }
072
073    public long getLastModified()
074    {
075        return lastModified;
076    }
077
078    public void streamTo(OutputStream os) throws IOException
079    {
080        bytestreamCache.writeTo(os);
081    }
082
083    public InputStream openStream() throws IOException
084    {
085        return bytestreamCache.openStream();
086    }
087
088    @Override
089    public String toString()
090    {
091        return String.format("StreamableResource<%s %s %s lastModified: %tc size: %d>", contentType, description, compression.name(),
092                lastModified, getSize());
093    }
094
095    public String getChecksum() throws IOException
096    {
097        // Currently, we rely on AssetChecksumGenerator to manage a cache, but that may be better done
098        // here (but must be threads-afe).
099        return assetChecksumGenerator.generateChecksum(this);
100    }
101
102    @Override
103    public StreamableResource addResponseCustomizer(final ResponseCustomizer customizer)
104    {
105        final ResponseCustomizer oldCustomizer = responseCustomizer;
106
107        if (oldCustomizer == null)
108        {
109            return withNewResourceCustomizer(customizer);
110        }
111
112        return withNewResourceCustomizer(new ResponseCustomizer()
113        {
114            @Override
115            public void customizeResponse(StreamableResource resource, Response response) throws IOException
116            {
117                oldCustomizer.customizeResponse(resource, response);
118                customizer.customizeResponse(resource, response);
119            }
120        });
121    }
122
123    @Override
124    public ResponseCustomizer getResponseCustomizer()
125    {
126        return responseCustomizer;
127    }
128
129    @Override
130    public StreamableResource withContentType(ContentType newContentType)
131    {
132        return new StreamableResourceImpl(description, newContentType, compression, lastModified, bytestreamCache, assetChecksumGenerator, responseCustomizer);
133    }
134
135    private StreamableResourceImpl withNewResourceCustomizer(ResponseCustomizer customizer)
136    {
137        return new StreamableResourceImpl(description, contentType, compression, lastModified, bytestreamCache, assetChecksumGenerator, customizer);
138    }
139}