    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.services.assets;
    016
    017    import org.apache.tapestry5.SymbolConstants;
    018    import org.apache.tapestry5.internal.services.assets.*;
    019    import org.apache.tapestry5.ioc.MappedConfiguration;
    020    import org.apache.tapestry5.ioc.ServiceBinder;
    021    import org.apache.tapestry5.ioc.annotations.*;
    022    import org.apache.tapestry5.ioc.services.FactoryDefaults;
    023    import org.apache.tapestry5.ioc.services.SymbolProvider;
    024    import org.apache.tapestry5.services.Core;
    025
    026    /**
    027     * @since 5.3
    028     */
    029    @Marker(Core.class)
    030    public class AssetsModule
    031    {
    032        public static void bind(ServiceBinder binder)
    033        {
    034            binder.bind(StreamableResourceSource.class, StreamableResourceSourceImpl.class);
    035            binder.bind(CompressionAnalyzer.class, CompressionAnalyzerImpl.class);
    036            binder.bind(ContentTypeAnalyzer.class, ContentTypeAnalyzerImpl.class);
    037            binder.bind(ResourceChangeTracker.class, ResourceChangeTrackerImpl.class);
    038            binder.bind(ResourceMinimizer.class, MasterResourceMinimizer.class);
    039        }
    040
    041        @Contribute(SymbolProvider.class)
    042        @FactoryDefaults
    043        public static void setupSymbols(MappedConfiguration<String, String> configuration)
    044        {
    045            configuration.add(SymbolConstants.MINIFICATION_ENABLED, SymbolConstants.PRODUCTION_MODE_VALUE);
    046            configuration.add(SymbolConstants.GZIP_COMPRESSION_ENABLED, "true");
    047            configuration.add(SymbolConstants.COMBINE_SCRIPTS, SymbolConstants.PRODUCTION_MODE_VALUE);
    048            configuration.add(SymbolConstants.ASSET_URL_FULL_QUALIFIED, "false");
    049        }
    050
    051        // The use of decorators is to allow third-parties to get their own extensions
    052        // into the pipeline.
    053
    054        @Decorate(id = "GZipCompression", serviceInterface = StreamableResourceSource.class)
    055        public StreamableResourceSource enableCompression(StreamableResourceSource delegate,
    056                                                          @Symbol(SymbolConstants.GZIP_COMPRESSION_ENABLED)
    057                                                          boolean gzipEnabled, @Symbol(SymbolConstants.MIN_GZIP_SIZE)
    058        int compressionCutoff)
    059        {
    060            return gzipEnabled ? new SRSCompressingInterceptor(compressionCutoff, delegate) : null;
    061        }
    062
    063        @Decorate(id = "CacheCompressed", serviceInterface = StreamableResourceSource.class)
    064        @Order("before:GZIpCompression")
    065        public StreamableResourceSource enableCompressedCaching(StreamableResourceSource delegate,
    066                                                                @Symbol(SymbolConstants.GZIP_COMPRESSION_ENABLED)
    067                                                                boolean gzipEnabled, ResourceChangeTracker tracker)
    068        {
    069            if (!gzipEnabled)
    070                return null;
    071
    072            SRSCompressedCachingInterceptor interceptor = new SRSCompressedCachingInterceptor(delegate);
    073
    074            tracker.addInvalidationListener(interceptor);
    075
    076            return interceptor;
    077        }
    078
    079        @Decorate(id = "Cache", serviceInterface = StreamableResourceSource.class)
    080        @Order("after:GZipCompression")
    081        public StreamableResourceSource enableUncompressedCaching(StreamableResourceSource delegate,
    082                                                                  ResourceChangeTracker tracker)
    083        {
    084            SRSCachingInterceptor interceptor = new SRSCachingInterceptor(delegate);
    085
    086            tracker.addInvalidationListener(interceptor);
    087
    088            return interceptor;
    089        }
    090
    091        @Decorate(id = "Minification", serviceInterface = StreamableResourceSource.class)
    092        @Order("after:Cache")
    093        public StreamableResourceSource enableMinification(StreamableResourceSource delegate, ResourceMinimizer minimizer,
    094                                                           @Symbol(SymbolConstants.MINIFICATION_ENABLED)
    095                                                           boolean enabled)
    096        {
    097            if (enabled)
    098                return new SRSMinimizingInterceptor(delegate, minimizer);
    099
    100            return null;
    101        }
    102
    103        /**
    104         * Adds content types:
    105         * <dl>
    106         * <dt>css</dt>
    107         * <dd>text/css</dd>
    108         * <dt>js</dt>
    109         * <dd>text/javascript</dd>
    110         * <dt>jpg, jpeg</dt>
    111         * <dd>image/jpeg</dd>
    112         * <dt>gif</dt>
    113         * <dd>image/gif</dd>
    114         * <dt>png</dt>
    115         * <dd>image/png</dd>
    116         * <dt>svg</dt>
    117         * <dd>image/svg+xml</dd>
    118         * <dt>swf</dt>
    119         * <dd>application/x-shockwave-flash</dd>
    120         * </dl>
    121         */
    122        @Contribute(ContentTypeAnalyzer.class)
    123        public void setupDefaultContentTypeMappings(MappedConfiguration<String, String> configuration)
    124        {
    125            configuration.add("css", "text/css");
    126            configuration.add("js", "text/javascript");
    127            configuration.add("gif", "image/gif");
    128            configuration.add("jpg", "image/jpeg");
    129            configuration.add("jpeg", "image/jpeg");
    130            configuration.add("png", "image/png");
    131            configuration.add("swf", "application/x-shockwave-flash");
    132            configuration.add("svg", "image/svg+xml");
    133        }
    134
    135        /**
    136         * Disables compression for the following content types:
    137         * <ul>
    138         * <li>image/jpeg</li>
    139         * <li>image/gif</li>
    140         * <li>image/png</li>
    141         * <li>application/x-shockwave-flash</li>
    142         * </ul>
    143         */
    144        @Contribute(CompressionAnalyzer.class)
    145        public void disableCompressionForImageTypes(MappedConfiguration<String, Boolean> configuration)
    146        {
    147            configuration.add("image/jpeg", false);
    148            configuration.add("image/gif", false);
    149            configuration.add("image/png", false);
    150            configuration.add("application/x-shockwave-flash", false);
    151        }
    152    }