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 }