Java tutorial
package org.codehaus.mojo.javascript; /* * Copyright 2001-2005 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. */ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.text.NumberFormat; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.metadata.ArtifactMetadataSource; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactResolutionResult; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.artifact.versioning.VersionRange; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.mojo.javascript.compress.CompressionException; import org.codehaus.mojo.javascript.compress.IsolatedClassLoader; import org.codehaus.mojo.javascript.compress.JSCompressor; import org.codehaus.mojo.javascript.compress.JSCompressorProxy; import org.codehaus.mojo.javascript.compress.JSMinCompressor; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; /** * Abstact mojo for compressing JavaScripts. * * @author <a href="mailto:nicolas@apache.org">nicolas De Loof</a> */ public abstract class AbstractCompressMojo extends AbstractMojo { /** * Resolves the artifacts and dependencies. * * @component */ private ArtifactResolver artifactResolver; /** * Create Artifact references * * @component */ private ArtifactFactory artifactFactory; /** * The local repository * * @parameter expression="${localRepository}" * @required */ private ArtifactRepository localRepository; /** * For retrieval of artifact's metadata. * * @component */ private ArtifactMetadataSource metadataSource; /** * The remote repositories declared in the pom. * * @parameter expression="${project.pluginArtifactRepositories}" */ private List remoteRepositories; /** * */ private static final NumberFormat INTEGER = NumberFormat.getIntegerInstance(); private static final String HR = StringUtils.rightPad("", 78, "-"); /** * The maven project we are working on. * * @parameter default-value="${project}" * @required * @readonly */ MavenProject project; /** * The available compressors */ private Map compressors = new HashMap(); { compressors.put("jsmin", new JSMinCompressor()); } /** * Optimization level, from 0 to 9 * * @parameter default-value="9" */ private int optimizationLevel; /** * JS Language version (130 for JS 1.3) * * @parameter default-value="130" */ private int languageVersion; /** * The compressor to used. Either "shrinksafe", "yahooui" or "jsmin" for default compressor, * or a custom one provided as an artifact in repo org.codehaus.mojo.javascript:<xxx>-compressor. * * @parameter default-value="jsmin" */ private String compressor; /** * Don't display compression stats * * @parameter */ private boolean skipStats; private static final String[] DEFAULT_INCLUDES = new String[] { "**/*.js" }; /** * Inclusion patterns * * @parameter */ private String[] includes; /** * Exclusion patterns * * @parameter */ private String[] excludes; /** * A special token to recognize lines to be removed from scripts (debugging * code). * * @parameter */ private String strip; /** * {@inheritDoc} * * @see org.apache.maven.plugin.AbstractMojo#execute() */ public void execute() throws MojoExecutionException { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir(getSourceDirectory()); if (includes == null) { includes = DEFAULT_INCLUDES; } scanner.setIncludes(includes); scanner.addDefaultExcludes(); if (excludes != null) { scanner.setExcludes(excludes); } scanner.scan(); String[] files = scanner.getIncludedFiles(); // if ( !Context.isValidOptimizationLevel( optimizationLevel ) ) // { // throw new MojoExecutionException( "optimizationLevel is invalid" ); // } // if ( !Context.isValidLanguageVersion( languageVersion ) ) // { // throw new MojoExecutionException( "languageVersion is invalid" ); // } JSCompressor jscompressor = getCompressor(); logStats(HR); getOutputDirectory().mkdirs(); long saved = 0; for (int i = 0; i < files.length; i++) { String file = files[i]; saved = compress(jscompressor, file); } logStats(HR); logStats("compression saved " + INTEGER.format(saved) + " bytes"); } private File stripDebugs(File file) throws MojoExecutionException { if (strip == null) { return file; } try { File stripped = File.createTempFile("stripped", ".js"); BufferedReader reader = new BufferedReader(new FileReader(file)); PrintWriter writer = new PrintWriter(stripped); String line; while ((line = reader.readLine()) != null) { if (!line.trim().startsWith(strip)) { writer.println(line); } } IOUtil.close(reader); IOUtil.close(writer); FileUtils.copyFile(stripped, file); stripped.delete(); } catch (IOException e) { throw new MojoExecutionException("Failed to strip debug code in " + file, e); } return file; } private JSCompressor getCompressor() throws MojoExecutionException { if (compressors.containsKey(compressor)) { return (JSCompressor) compressors.get(compressor); } // Inspired by the surefire plugin // allows to use multiple compressor that rely on modifier Rhino engines // without dependencies/classpath conflicts String id = compressor.toLowerCase() + "-compressor"; // TODO don't have version hardcoded Artifact compressorArtifact = artifactFactory.createDependencyArtifact("org.codehaus.mojo.javascript", id, VersionRange.createFromVersion("1.0-alpha-1-SNAPSHOT"), "jar", null, Artifact.SCOPE_RUNTIME); Artifact originatingArtifact = artifactFactory.createBuildArtifact("dummy", "dummy", "1.0", "jar"); ArtifactResolutionResult dependencies; try { dependencies = artifactResolver.resolveTransitively(Collections.singleton(compressorArtifact), originatingArtifact, localRepository, remoteRepositories, metadataSource, null); } catch (Exception e) { getLog().info("Failed to load compressor artifact " + compressorArtifact.toString()); throw new MojoExecutionException("Failed to load compressor artifact" + compressorArtifact.toString(), e); } IsolatedClassLoader classLoader = new IsolatedClassLoader(dependencies.getArtifacts()); compressor = StringUtils.capitalize(compressor); String compressorClassName = "org.codehaus.mojo.javascript.compress." + compressor + "Compressor"; Class compressorClass; try { compressorClass = classLoader.loadClass(compressorClassName); } catch (ClassNotFoundException e) { getLog().info("Failed to load compressor class " + compressorClassName); throw new MojoExecutionException("Failed to load compressor class" + compressorClassName, e); } JSCompressor jscompressor; try { jscompressor = new JSCompressorProxy(compressorClass.newInstance()); } catch (Exception e) { getLog().info("Failed to create a isolated-classloader proxy for " + compressorClassName); throw new MojoExecutionException( "Failed to create a isolated-classloader proxy for " + compressorClassName, e); } getLog().info("Compressing javascript using " + compressor); compressors.put(compressor, jscompressor); return jscompressor; } private long compress(JSCompressor jscompressor, String file) throws MojoExecutionException { String name = file; if (getExtension() != null) { int ext = file.lastIndexOf('.'); name = file.substring(0, ext) + "-" + getExtension() + file.substring(ext); } File compressed = new File(getOutputDirectory(), name); compressed.getParentFile().mkdirs(); File in = new File(getSourceDirectory(), file); if (in.equals(compressed)) { try { File temp = File.createTempFile("compress", ".js"); long size = compress(in, temp, jscompressor); FileUtils.copyFile(temp, compressed); temp.delete(); return size; } catch (IOException e) { throw new MojoExecutionException("Error creating temp file for compression", e); } } else { return compress(in, compressed, jscompressor); } } private long compress(File in, File compressed, JSCompressor jscompressor) throws MojoExecutionException { if (in.length() > 0) { File stripped = stripDebugs(in); try { jscompressor.compress(stripped, compressed, optimizationLevel, languageVersion); } catch (CompressionException e) { throw new MojoExecutionException("Failed to compress Javascript file " + e.getScript(), e); } String describe = in.getName() + " (" + INTEGER.format(in.length()) + " bytes) "; String title = StringUtils.rightPad(describe, 60, "."); logStats(title + " compressed at " + ratio(compressed, in) + "%"); return in.length() - compressed.length(); } else { try { compressed.createNewFile(); getLog().info(in.getName() + " was zero length; not compressed."); return 0; } catch (IOException e) { throw new MojoExecutionException("Error handling zero length file.", e); } } } private long ratio(File compressed, File in) { long length = in.length(); if (length == 0) { return 0; } return (((length - compressed.length()) * 100) / length); } private void logStats(String line) { if (skipStats) { return; } getLog().info(line); } /** * @return the extension to append to compressed scripts. */ public abstract String getExtension(); /** * @return the outputDirectory */ protected abstract File getOutputDirectory(); /** * @return the sourceDirectory */ protected abstract File getSourceDirectory(); protected void setLocalRepository(ArtifactRepository localRepository) { this.localRepository = localRepository; } }