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    }