    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.ContentType;
    016import org.apache.tapestry5.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}