Author: hlship Date: Wed Mar 2 21:39:04 2011 New Revision: 1076400 URL: http://svn.apache.org/viewvc?rev=1076400&view=rev Log: TAP5-73: Define the ResourceMinimizer service (as a do-nothing placeholder) and thread it into StreamableResourceSource and StackAssetRequestHandler
Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/DefaultResourceMinimizer.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/SRSMinimizingInterceptor.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceMinimizer.java Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetsModule.java Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java Wed Mar 2 21:39:04 2011 @@ -17,6 +17,7 @@ package org.apache.tapestry5; import org.apache.tapestry5.internal.services.AssetDispatcher; import org.apache.tapestry5.services.ComponentClassTransformWorker; import org.apache.tapestry5.services.assets.AssetPathConstructor; +import org.apache.tapestry5.services.assets.ResourceMinimizer; import org.apache.tapestry5.services.javascript.JavaScriptStack; /** @@ -325,19 +326,23 @@ public class SymbolConstants * @since 5.2.0 */ public static final String PAGE_POOL_ENABLED = "tapestry.page-pool-enabled"; - + /** - * If "true" and {@link #PRODUCTION_MODE} is off, comments will be rendered before and after the rendering of any component - * allowing more visibility into which components rendered which markup. Defaults to "false". Component render tracing may be + * If "true" and {@link #PRODUCTION_MODE} is off, comments will be rendered before and after the rendering of any + * component + * allowing more visibility into which components rendered which markup. Defaults to "false". Component render + * tracing may be * enabled per-request by the presence of a request parameter "t:component-trace" with a value of "true". * * @since 5.2.5 */ public static final String COMPONENT_RENDER_TRACING_ENABLED = "tapestry.component-render-tracing-enabled"; - + /** - * The hostname that application should use when constructing an absolute URL. The default is "", i.e. an empty string, - * in which case system will use request.getServerName(). Not the same as environment variable HOSTNAME, but you can also + * The hostname that application should use when constructing an absolute URL. The default is "", i.e. an empty + * string, + * in which case system will use request.getServerName(). Not the same as environment variable HOSTNAME, but you can + * also * contribute "$HOSTNAME" as the value to make it the same as the environment variable HOSTNAME. * * @since 5.3.0 @@ -345,18 +350,32 @@ public class SymbolConstants public static final String HOSTNAME = "tapestry.hostname"; /** - * The hostport that application should use when constructing an absolute URL. The default is "0", i.e. use the port value from + * The hostport that application should use when constructing an absolute URL. The default is "0", i.e. use the port + * value from * the request. * * @since 5.3.0 */ public static final String HOSTPORT = "tapestry.hostport"; - + /** - * The secure (https) hostport that application should use when constructing an absolute URL. The default is "0", i.e. use + * The secure (https) hostport that application should use when constructing an absolute URL. The default is "0", + * i.e. use * the value from the request. * * @since 5.3.0 */ public static final String HOSTPORT_SECURE = "tapestry.hostport-secure"; + + /** + * If "true", then resources (individually or when aggregated into stacks) will be minimized via the + * {@link ResourceMinimizer} service. If "false", then minification is disabled. Tracks production mode + * (minification is normally disabled in development mode). + * <p> + * Note that Tapestry's default implementation of {@link ResourceMinimizer} does nothing; minification is provided + * by add-on libraries. + * + * @since 5.3.0 + */ + public static final String MINIFICATION_ENABLED = "tapestry.enable-minification"; } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamer.java Wed Mar 2 21:39:04 2011 @@ -19,6 +19,7 @@ import java.io.IOException; import javax.servlet.http.HttpServletResponse; import org.apache.tapestry5.ioc.Resource; +import org.apache.tapestry5.services.assets.StreamableResource; import org.apache.tapestry5.services.assets.StreamableResourceSource; /** @@ -37,4 +38,13 @@ public interface ResourceStreamer * @see StreamableResourceSource */ void streamResource(Resource resource) throws IOException; + + /** + * Streams a resource that has been assembled elsewhere. + * + * @param resource + * @throws IOException + * @since 5.3.0 + */ + void streamResource(StreamableResource resource) throws IOException; } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java Wed Mar 2 21:39:04 2011 @@ -73,15 +73,20 @@ public class ResourceStreamerImpl implem return; } - long ifModifiedSince = 0; - StreamableResourceProcessing processing = analyzer.isGZipSupported() ? StreamableResourceProcessing.COMPRESSION_ENABLED : StreamableResourceProcessing.COMPRESSION_DISABLED; StreamableResource streamable = streamableResourceSource.getStreamableResource(resource, processing); + streamResource(streamable); + } + + public void streamResource(StreamableResource streamable) throws IOException + { long lastModified = streamable.getLastModified(); + long ifModifiedSince = 0; + try { ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE_HEADER); Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/DefaultResourceMinimizer.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/DefaultResourceMinimizer.java?rev=1076400&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/DefaultResourceMinimizer.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/DefaultResourceMinimizer.java Wed Mar 2 21:39:04 2011 @@ -0,0 +1,32 @@ +// Copyright 2011 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.internal.services.assets; + +import java.io.IOException; + +import org.apache.tapestry5.services.assets.ResourceMinimizer; +import org.apache.tapestry5.services.assets.StreamableResource; + +/** + * Default implementation that simply returns the resource unchanged. + */ +public class DefaultResourceMinimizer implements ResourceMinimizer +{ + /** Does nothing; an override of this service can be installed to provide minimization. */ + public StreamableResource minimize(StreamableResource resource) throws IOException + { + return resource; + } +} Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/SRSMinimizingInterceptor.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/SRSMinimizingInterceptor.java?rev=1076400&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/SRSMinimizingInterceptor.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/SRSMinimizingInterceptor.java Wed Mar 2 21:39:04 2011 @@ -0,0 +1,51 @@ +// Copyright 2011 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.internal.services.assets; + +import java.io.IOException; + +import org.apache.tapestry5.ioc.Resource; +import org.apache.tapestry5.services.assets.ResourceMinimizer; +import org.apache.tapestry5.services.assets.StreamableResource; +import org.apache.tapestry5.services.assets.StreamableResourceProcessing; +import org.apache.tapestry5.services.assets.StreamableResourceSource; + +/** + * Loops the result through the {@link ResourceMinimizer} service. + */ +public class SRSMinimizingInterceptor implements StreamableResourceSource +{ + private final StreamableResourceSource delegate; + + private final ResourceMinimizer minimizer; + + public SRSMinimizingInterceptor(StreamableResourceSource delegate, ResourceMinimizer minimizer) + { + this.delegate = delegate; + this.minimizer = minimizer; + } + + public StreamableResource getStreamableResource(Resource baseResource, StreamableResourceProcessing processing) + throws IOException + { + StreamableResource streamable = delegate.getStreamableResource(baseResource, processing); + + if (processing != StreamableResourceProcessing.FOR_AGGREGATION) + return minimizer.minimize(streamable); + + return streamable; + } + +} Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java Wed Mar 2 21:39:04 2011 @@ -14,6 +14,7 @@ package org.apache.tapestry5.internal.services.assets; +import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -27,7 +28,7 @@ import java.util.zip.GZIPOutputStream; import org.apache.tapestry5.Asset; import org.apache.tapestry5.SymbolConstants; -import org.apache.tapestry5.internal.InternalConstants; +import org.apache.tapestry5.internal.services.ResourceStreamer; import org.apache.tapestry5.ioc.Resource; import org.apache.tapestry5.ioc.annotations.PostInjection; import org.apache.tapestry5.ioc.annotations.Symbol; @@ -39,6 +40,8 @@ import org.apache.tapestry5.services.Req import org.apache.tapestry5.services.Response; import org.apache.tapestry5.services.ResponseCompressionAnalyzer; import org.apache.tapestry5.services.assets.AssetRequestHandler; +import org.apache.tapestry5.services.assets.CompressionStatus; +import org.apache.tapestry5.services.assets.ResourceMinimizer; import org.apache.tapestry5.services.assets.StreamableResource; import org.apache.tapestry5.services.assets.StreamableResourceProcessing; import org.apache.tapestry5.services.assets.StreamableResourceSource; @@ -47,6 +50,8 @@ import org.apache.tapestry5.services.jav public class StackAssetRequestHandler implements AssetRequestHandler, InvalidationListener { + private static final String JAVASCRIPT_CONTENT_TYPE = "text/javascript"; + private final StreamableResourceSource streamableResourceSource; private final JavaScriptStackSource javascriptStackSource; @@ -55,27 +60,34 @@ public class StackAssetRequestHandler im private final ResponseCompressionAnalyzer compressionAnalyzer; - private final boolean productionMode; + private final ResourceStreamer resourceStreamer; private final Pattern pathPattern = Pattern.compile("^(.+)/(.+)\\.js$"); // Two caches, keyed on extra path. Both are accessed only from synchronized blocks. - private final Map<String, BytestreamCache> uncompressedCache = CollectionFactory.newCaseInsensitiveMap(); + private final Map<String, StreamableResource> uncompressedCache = CollectionFactory.newCaseInsensitiveMap(); + + private final Map<String, StreamableResource> compressedCache = CollectionFactory.newCaseInsensitiveMap(); + + private final ResourceMinimizer resourceMinimizer; - private final Map<String, BytestreamCache> compressedCache = CollectionFactory.newCaseInsensitiveMap(); + private final boolean minificationEnabled; public StackAssetRequestHandler(StreamableResourceSource streamableResourceSource, JavaScriptStackSource javascriptStackSource, LocalizationSetter localizationSetter, - ResponseCompressionAnalyzer compressionAnalyzer, + ResponseCompressionAnalyzer compressionAnalyzer, ResourceStreamer resourceStreamer, + ResourceMinimizer resourceMinimizer, - @Symbol(SymbolConstants.PRODUCTION_MODE) - boolean productionMode) + @Symbol(SymbolConstants.MINIFICATION_ENABLED) + boolean minificationEnabled) { this.streamableResourceSource = streamableResourceSource; this.javascriptStackSource = javascriptStackSource; this.localizationSetter = localizationSetter; this.compressionAnalyzer = compressionAnalyzer; - this.productionMode = productionMode; + this.resourceStreamer = resourceStreamer; + this.resourceMinimizer = resourceMinimizer; + this.minificationEnabled = minificationEnabled; } @PostInjection @@ -88,32 +100,9 @@ public class StackAssetRequestHandler im { boolean compress = compressionAnalyzer.isGZipSupported(); - BytestreamCache cachedStream = getStream(extraPath, compress); - - // The whole point of this is to force the client to aggressively cache the combined, virtual - // stack asset. - - long lastModified = System.currentTimeMillis(); - response.setDateHeader("Last-Modified", lastModified); - - if (productionMode) - response.setDateHeader("Expires", lastModified + InternalConstants.TEN_YEARS); - - response.disableCompression(); - - response.setContentLength(cachedStream.size()); - - if (compress) - response.setHeader(InternalConstants.CONTENT_ENCODING_HEADER, InternalConstants.GZIP_CONTENT_ENCODING); - - // CSS aggregation is problematic, because of relative URLs inside the CSS files. For the - // moment, only JavaScript is supported. - - OutputStream output = response.getOutputStream("text/javascript"); - - cachedStream.writeTo(output); + StreamableResource resource = getResource(extraPath, compress); - output.close(); + resourceStreamer.streamResource(resource); return true; } @@ -125,18 +114,18 @@ public class StackAssetRequestHandler im compressedCache.clear(); } - private BytestreamCache getStream(String extraPath, boolean compressed) throws IOException + private StreamableResource getResource(String extraPath, boolean compressed) throws IOException { - return compressed ? getCompressedStream(extraPath) : getUncompressedStream(extraPath); + return compressed ? getCompressedResource(extraPath) : getUncompressedResource(extraPath); } - private synchronized BytestreamCache getCompressedStream(String extraPath) throws IOException + private synchronized StreamableResource getCompressedResource(String extraPath) throws IOException { - BytestreamCache result = compressedCache.get(extraPath); + StreamableResource result = compressedCache.get(extraPath); if (result == null) { - BytestreamCache uncompressed = getUncompressedStream(extraPath); + StreamableResource uncompressed = getUncompressedResource(extraPath); result = compressStream(uncompressed); compressedCache.put(extraPath, result); } @@ -144,9 +133,9 @@ public class StackAssetRequestHandler im return result; } - private synchronized BytestreamCache getUncompressedStream(String extraPath) throws IOException + private synchronized StreamableResource getUncompressedResource(String extraPath) throws IOException { - BytestreamCache result = uncompressedCache.get(extraPath); + StreamableResource result = uncompressedCache.get(extraPath); if (result == null) { @@ -157,7 +146,7 @@ public class StackAssetRequestHandler im return result; } - private BytestreamCache assembleStackContent(String extraPath) throws IOException + private StreamableResource assembleStackContent(String extraPath) throws IOException { Matcher matcher = pathPattern.matcher(extraPath); @@ -170,21 +159,24 @@ public class StackAssetRequestHandler im return assembleStackContent(localeName, stackName); } - private BytestreamCache assembleStackContent(String localeName, String stackName) throws IOException + private StreamableResource assembleStackContent(String localeName, String stackName) throws IOException { localizationSetter.setNonPeristentLocaleFromLocaleName(localeName); JavaScriptStack stack = javascriptStackSource.getStack(stackName); List<Asset> libraries = stack.getJavaScriptLibraries(); - return assembleStackContent(libraries); + StreamableResource stackContent = assembleStackContent(libraries); + + return minificationEnabled ? resourceMinimizer.minimize(stackContent) : stackContent; } - private BytestreamCache assembleStackContent(List<Asset> libraries) throws IOException + private StreamableResource assembleStackContent(List<Asset> libraries) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(stream, "UTF-8"); PrintWriter writer = new PrintWriter(osw, true); + long lastModified = 0; JSONArray paths = new JSONArray(); @@ -196,36 +188,36 @@ public class StackAssetRequestHandler im writer.format("\n/* %s */;\n", path); - streamLibraryContent(library, stream); - } + Resource resource = library.getResource(); - writer.format("\n;/**/\nTapestry.markScriptLibrariesLoaded(%s);\n", paths); + StreamableResource streamable = streamableResourceSource.getStreamableResource(resource, + StreamableResourceProcessing.FOR_AGGREGATION); - writer.close(); + streamable.streamTo(stream); - return new BytestreamCache(stream); - } + lastModified = Math.max(lastModified, streamable.getLastModified()); + } - private void streamLibraryContent(Asset library, OutputStream outputStream) throws IOException - { - Resource resource = library.getResource(); + writer.format("\n;/**/\nTapestry.markScriptLibrariesLoaded(%s);\n", paths); - StreamableResource streamable = streamableResourceSource.getStreamableResource(resource, - StreamableResourceProcessing.FOR_AGGREGATION); + writer.close(); - streamable.streamTo(outputStream); + return new StreamableResourceImpl(JAVASCRIPT_CONTENT_TYPE, CompressionStatus.COMPRESSABLE, lastModified, + new BytestreamCache(stream)); } - private BytestreamCache compressStream(BytestreamCache uncompressed) throws IOException + private StreamableResource compressStream(StreamableResource uncompressed) throws IOException { ByteArrayOutputStream compressed = new ByteArrayOutputStream(); - OutputStream compressor = new GZIPOutputStream(compressed); + OutputStream compressor = new BufferedOutputStream(new GZIPOutputStream(compressed)); - uncompressed.writeTo(compressor); + uncompressed.streamTo(compressor); compressor.close(); - return new BytestreamCache(compressed); - } + BytestreamCache cache = new BytestreamCache(compressed); + return new StreamableResourceImpl(JAVASCRIPT_CONTENT_TYPE, CompressionStatus.COMPRESSED, + uncompressed.getLastModified(), cache); + } } Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Wed Mar 2 21:39:04 2011 @@ -2470,10 +2470,8 @@ public final class TapestryModule configuration.add(SymbolConstants.APPLICATION_VERSION, Long.toHexString(random.nextLong())); configuration.add(SymbolConstants.OMIT_GENERATOR_META, "false"); - configuration.add(SymbolConstants.GZIP_COMPRESSION_ENABLED, "true"); configuration.add(SymbolConstants.SECURE_ENABLED, SymbolConstants.PRODUCTION_MODE_VALUE); - configuration.add(SymbolConstants.COMBINE_SCRIPTS, SymbolConstants.PRODUCTION_MODE_VALUE); configuration.add(SymbolConstants.COMPACT_JSON, SymbolConstants.PRODUCTION_MODE_VALUE); configuration.add(SymbolConstants.ENCODE_LOCALE_INTO_PATH, "true"); Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetsModule.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetsModule.java?rev=1076400&r1=1076399&r2=1076400&view=diff ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetsModule.java (original) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetsModule.java Wed Mar 2 21:39:04 2011 @@ -17,11 +17,13 @@ package org.apache.tapestry5.services.as import org.apache.tapestry5.SymbolConstants; import org.apache.tapestry5.internal.services.assets.CompressionAnalyzerImpl; import org.apache.tapestry5.internal.services.assets.ContentTypeAnalyzerImpl; +import org.apache.tapestry5.internal.services.assets.DefaultResourceMinimizer; import org.apache.tapestry5.internal.services.assets.ResourceChangeTracker; import org.apache.tapestry5.internal.services.assets.ResourceChangeTrackerImpl; import org.apache.tapestry5.internal.services.assets.SRSCachingInterceptor; import org.apache.tapestry5.internal.services.assets.SRSCompressedCachingInterceptor; import org.apache.tapestry5.internal.services.assets.SRSCompressingInterceptor; +import org.apache.tapestry5.internal.services.assets.SRSMinimizingInterceptor; import org.apache.tapestry5.internal.services.assets.StreamableResourceSourceImpl; import org.apache.tapestry5.ioc.MappedConfiguration; import org.apache.tapestry5.ioc.ServiceBinder; @@ -30,6 +32,8 @@ import org.apache.tapestry5.ioc.annotati import org.apache.tapestry5.ioc.annotations.Marker; import org.apache.tapestry5.ioc.annotations.Order; import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.services.FactoryDefaults; +import org.apache.tapestry5.ioc.services.SymbolProvider; import org.apache.tapestry5.services.Core; /** @@ -44,6 +48,16 @@ public class AssetsModule binder.bind(CompressionAnalyzer.class, CompressionAnalyzerImpl.class); binder.bind(ContentTypeAnalyzer.class, ContentTypeAnalyzerImpl.class); binder.bind(ResourceChangeTracker.class, ResourceChangeTrackerImpl.class); + binder.bind(ResourceMinimizer.class, DefaultResourceMinimizer.class); + } + + @Contribute(SymbolProvider.class) + @FactoryDefaults + public static void setupSymbols(MappedConfiguration<String, String> configuration) + { + configuration.add(SymbolConstants.MINIFICATION_ENABLED, SymbolConstants.PRODUCTION_MODE_VALUE); + configuration.add(SymbolConstants.GZIP_COMPRESSION_ENABLED, "true"); + configuration.add(SymbolConstants.COMBINE_SCRIPTS, SymbolConstants.PRODUCTION_MODE_VALUE); } // The use of decorators is to allow third-parties to get their own extensions @@ -67,8 +81,7 @@ public class AssetsModule if (!gzipEnabled) return null; - SRSCompressedCachingInterceptor interceptor = new SRSCompressedCachingInterceptor(tracker, - delegate); + SRSCompressedCachingInterceptor interceptor = new SRSCompressedCachingInterceptor(tracker, delegate); tracker.addInvalidationListener(interceptor); @@ -87,6 +100,18 @@ public class AssetsModule return interceptor; } + @Decorate(id = "Minification", serviceInterface = StreamableResourceSource.class) + @Order("after:Cache") + public StreamableResourceSource enableMinification(StreamableResourceSource delegate, ResourceMinimizer minimizer, + @Symbol(SymbolConstants.MINIFICATION_ENABLED) + boolean enabled) + { + if (enabled) + return new SRSMinimizingInterceptor(delegate, minimizer); + + return null; + } + /** * Adds content types: * <dl> Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceMinimizer.java URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceMinimizer.java?rev=1076400&view=auto ============================================================================== --- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceMinimizer.java (added) +++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResourceMinimizer.java Wed Mar 2 21:39:04 2011 @@ -0,0 +1,38 @@ +// Copyright 2011 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.apache.tapestry5.services.assets; + +import java.io.IOException; + +/** + * Certain kinds of resources can be minimized: this primarily refers to JavaScript and CSS, both of which contain + * whitespace, comments and other features that can be reduced. + * + * @since 5.3.0 + */ +public interface ResourceMinimizer +{ + /** + * Checks the {@linkplain StreamableResource#getContentType() content type} of the resource and applies an + * appropriate + * minimization to it if possible. + * + * @param resource + * to minimize + * @return the same resource, or a minimized replacement for the resource + * @throws IOException + */ + StreamableResource minimize(StreamableResource resource) throws IOException; +}