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
015package org.apache.tapestry5.services.assets;
016
017import org.apache.tapestry5.SymbolConstants;
018import org.apache.tapestry5.internal.services.assets.*;
019import org.apache.tapestry5.ioc.MappedConfiguration;
020import org.apache.tapestry5.ioc.ServiceBinder;
021import org.apache.tapestry5.ioc.annotations.*;
022import org.apache.tapestry5.ioc.services.FactoryDefaults;
023import org.apache.tapestry5.ioc.services.SymbolProvider;
024import org.apache.tapestry5.services.Core;
025
026/**
027 * @since 5.3
028 */
029@Marker(Core.class)
030public 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}