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 }