All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.precompress.linker.PrecompressLinker Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2010 Google Inc.
 *
 * 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 com.google.gwt.precompress.linker;

import com.google.gwt.core.ext.LinkerContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.AbstractLinker;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.ConfigurationProperty;
import com.google.gwt.core.ext.linker.EmittedArtifact;
import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility;
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.linker.Shardable;
import com.google.gwt.dev.util.collect.HashSet;
import com.google.gwt.util.regexfilter.RegexFilter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
import java.util.zip.Deflater;
import java.util.zip.GZIPOutputStream;

/**
 * 

* A linker that precompresses the public artifacts that it sees. That way, a * web server that uses gzip transfer encoding can use the precompressed files * instead of having to compress them on the fly. * *

* To use this linker, add the following to your module definition: * *

 *   <inherits name="com.google.gwt.precompress.Precompress"/>
 * 
* *

* The files to precompress are specified by the configuration property * precompress.path.regexes. By default, the uncompressed artifacts * are left in the artifact set. If the configuration property * precompress.leave.originals is set to false, * however, then the uncompressed version is removed. */ @Shardable @LinkerOrder(Order.POST) public class PrecompressLinker extends AbstractLinker { private static class PrecompressFilter extends RegexFilter { public PrecompressFilter(TreeLogger logger, List regexes) throws UnableToCompleteException { super(logger, regexes); } @Override protected boolean acceptByDefault() { return false; } @Override protected boolean entriesArePositiveByDefault() { return true; } } /** * Buffer size to use when streaming data from artifacts and through * {@link GZIPOutputStream}. */ private static final int BUF_SIZE = 10000; private static final String PROP_LEAVE_ORIGINALS = "precompress.leave.originals"; private static final String PROP_PATH_REGEXES = "precompress.path.regexes"; private static ConfigurationProperty findProperty( TreeLogger logger, Iterable properties, String propName) throws UnableToCompleteException { for (ConfigurationProperty prop : properties) { if (prop.getName().equals(propName)) { return prop; } } logger.log(TreeLogger.ERROR, "Could not find configuration property " + propName); throw new UnableToCompleteException(); } @Override public String getDescription() { return "PrecompressLinker"; } @Override public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts, boolean onePermutation) throws UnableToCompleteException { ConfigurationProperty leaveOriginalsProp = findProperty(logger, context.getConfigurationProperties(), PROP_LEAVE_ORIGINALS); boolean leaveOriginals = Boolean.valueOf(leaveOriginalsProp.getValues().get( 0)); PrecompressFilter filter = new PrecompressFilter(logger.branch( TreeLogger.TRACE, "Analyzing the path patterns"), findProperty(logger, context.getConfigurationProperties(), PROP_PATH_REGEXES).getValues()); // Record the list of all paths for later lookup Set allPaths = new HashSet(); for (EmittedArtifact art : artifacts.find(EmittedArtifact.class)) { allPaths.add(art.getPartialPath()); } try { // Buffer for streaming data to be compressed byte[] buf = new byte[BUF_SIZE]; ArtifactSet updated = new ArtifactSet(artifacts); for (EmittedArtifact art : artifacts.find(EmittedArtifact.class)) { if (art.getVisibility() != Visibility.Public) { // only compress things that will be served to the client continue; } if (art.getPartialPath().endsWith(".gz")) { // Already a compressed artifact continue; } if (allPaths.contains(art.getPartialPath() + ".gz")) { // It's already been compressed continue; } if (!filter.isIncluded(logger.branch(TreeLogger.TRACE, "Checking the path patterns"), art.getPartialPath())) { continue; } TreeLogger compressBranch = logger.branch(TreeLogger.TRACE, "Compressing " + art.getPartialPath()); InputStream originalBytes = art.getContents(compressBranch); ByteArrayOutputStream compressedBytes = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(compressedBytes) { { def.setLevel(Deflater.BEST_COMPRESSION); } }; int originalLength = 0; int n; while ((n = originalBytes.read(buf)) > 0) { originalLength += n; gzip.write(buf, 0, n); } gzip.close(); byte[] compressed = compressedBytes.toByteArray(); if (compressed.length < originalLength) { updated.add(emitBytes(compressBranch, compressed, art.getPartialPath() + ".gz")); if (!leaveOriginals) { updated.remove(art); } } } return updated; } catch (IOException e) { logger.log(TreeLogger.ERROR, "Unexpected exception", e); throw new UnableToCompleteException(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy