    001// Copyright 2013 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
    015package org.apache.tapestry5.internal.services;
    016
    017import java.io.IOException;
    018
    019import org.apache.tapestry5.Asset;
    020import org.apache.tapestry5.commons.Resource;
    021import org.apache.tapestry5.commons.util.ExceptionUtils;
    022import org.apache.tapestry5.http.services.ResponseCompressionAnalyzer;
    023import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker;
    024import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    025import org.apache.tapestry5.services.AssetFactory;
    026import org.apache.tapestry5.services.assets.AssetPathConstructor;
    027import org.apache.tapestry5.services.assets.StreamableResource;
    028import org.apache.tapestry5.services.assets.StreamableResourceProcessing;
    029import org.apache.tapestry5.services.assets.StreamableResourceSource;
    030
    031public abstract class AbstractAssetFactory implements AssetFactory
    032{
    033    private final AssetPathConstructor assetPathConstructor;
    034
    035    private final ResponseCompressionAnalyzer compressionAnalyzer;
    036
    037    private final StreamableResourceSource streamableResourceSource;
    038
    039    private final ResourceChangeTracker resourceChangeTracker;
    040
    041    private final Resource rootResource;
    042
    043    public AbstractAssetFactory(ResponseCompressionAnalyzer compressionAnalyzer,
    044                                ResourceChangeTracker resourceChangeTracker,
    045                                StreamableResourceSource streamableResourceSource,
    046                                AssetPathConstructor assetPathConstructor,
    047                                Resource rootResource)
    048    {
    049        this.compressionAnalyzer = compressionAnalyzer;
    050        this.resourceChangeTracker = resourceChangeTracker;
    051        this.streamableResourceSource = streamableResourceSource;
    052        this.assetPathConstructor = assetPathConstructor;
    053        this.rootResource = rootResource;
    054    }
    055
    056    protected boolean isCompressable(StreamableResource resource)
    057    {
    058        return compressionAnalyzer.isGZipEnabled(resource.getContentType());
    059    }
    060
    061    /**
    062     * Returns the root {@link ContextResource}.
    063     */
    064    public Resource getRootResource()
    065    {
    066        return rootResource;
    067    }
    068
    069    protected Asset createAsset(final Resource resource, final String folder, final String resourcePath)
    070    {
    071        assert resource != null;
    072        assert InternalUtils.isNonBlank(folder);
    073        assert InternalUtils.isNonBlank(resourcePath);
    074
    075        return new AbstractAsset(false)
    076        {
    077            public String toClientURL()
    078            {
    079                // TODO: Some caching to ensure this is fast!  Fortunately, the SRS pipeline includes caching already,
    080                // but the results of assetPathConstructor could be cached as well, maybe.
    081
    082                try
    083                {
    084                    // Get the uncompressed version, so that we can identify its content type (and remember, the extension is not enough,
    085                    // as some types get translated to new content types by the SRS).
    086
    087                    StreamableResource uncompressed = streamableResourceSource.getStreamableResource(resource, StreamableResourceProcessing.COMPRESSION_DISABLED, resourceChangeTracker);
    088
    089                    StreamableResource forRequest = isCompressable(uncompressed)
    090                            ? streamableResourceSource.getStreamableResource(resource, StreamableResourceProcessing.COMPRESSION_ENABLED, resourceChangeTracker)
    091                            : uncompressed;
    092
    093                    return assetPathConstructor.constructAssetPath(folder, resourcePath, forRequest);
    094                } catch (IOException ex)
    095                {
    096                    throw new RuntimeException(String.format("Unable to construct asset path for %s: %s",
    097                            resource, ExceptionUtils.toMessage(ex)), ex);
    098                }
    099            }
    100
    101            public Resource getResource()
    102            {
    103                return resource;
    104            }
    105        };
    106
    107    }
    108}