org.codehaus.mojo.gwt.shell.CompileMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.mojo.gwt.shell.CompileMojo.java

Source

package org.codehaus.mojo.gwt.shell;

/*
 * CompileMojo.java
 *
 * Created on January 13, 2007, 11:42 AM
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 *
 */

import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;

import java.io.File;
import java.util.Collection;
import java.util.HashSet;

import org.apache.commons.lang.SystemUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.mojo.gwt.GwtModule;
import org.codehaus.mojo.gwt.utils.GwtModuleReaderException;
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;

/**
 * Invokes the GWTCompiler for the project source.
 * See compiler options :
 * http://code.google.com/intl/fr-FR/webtoolkit/doc/latest/DevGuideCompilingAndDebugging.html#DevGuideCompilerOptions
 *
 * @phase prepare-package
 * @goal compile
 * @requiresDependencyResolution compile
 * @version $Id$
 * @author cooper
 * @author ccollins
 * @author <a href="mailto:nicolas@apache.org">Nicolas De loof</a>
 * @author <a href="mailto:olamy@apache.org">Olivier Lamy</a>
 */
public class CompileMojo extends AbstractGwtShellMojo {

    /**
     * @parameter expression="${gwt.compiler.skip}" default-value="false"
     */
    private boolean skip;

    /**
     * Don't try to detect if GWT compilation is up-to-date and can be skipped.
     * <p>
     * Can be set from command line using '-Dgwt.compiler.force=true'.
     * </p>
     * @parameter expression="${gwt.compiler.force}" default-value="false"
     */
    private boolean force;

    /**
     * On GWT 1.6+, number of parallel processes used to compile GWT premutations. Defaults to
     * platform available processors number.
     * 
     * <p>
     * Can be unset from command line using '-Dgwt.compiler.localWorkers=n'.
     * </p>
     * 
     * @parameter expression="${gwt.compiler.localWorkers}"
     */
    private int localWorkers;

    /**
     * Whether or not to enable assertions in generated scripts (-ea).
     *
     * @parameter default-value="false"
     */
    private boolean enableAssertions;

    /**
     * Logs output in a graphical tree view.
     * <p>
     * Can be set from command line using '-Dgwt.treeLogger=true'.
     * </p>
     *
     * @parameter default-value="false" expression="${gwt.treeLogger}"
     */
    private boolean treeLogger;

    /**
     * EXPERIMENTAL: Disables some java.lang.Class methods (e.g. getName()).
     * <p>
     * Can be set from command line using '-Dgwt.disableClassMetadata=true'.
     * </p>
     *
     * @parameter default-value="false" expression="${gwt.disableClassMetadata}"
     */
    private boolean disableClassMetadata;

    /**
     * EXPERIMENTAL: Disables run-time checking of cast operations.
     * <p>
     * Can be set from command line using '-Dgwt.disableCastChecking=true'.
     * </p>
     *
     * @parameter default-value="false" expression="${gwt.disableCastChecking}"
     */
    private boolean disableCastChecking;

    /**
     * Validate all source code, but do not compile.
     * <p>
     * Can be set from command line using '-Dgwt.validateOnly=true'.
     * </p>
     *
     * @parameter default-value="false" expression="${gwt.validateOnly}"
     */
    private boolean validateOnly;

    /**
     * Enable faster, but less-optimized, compilations.
     * <p>
     * Can be set from command line using '-Dgwt.draftCompile=true'.
     * </p>
     *
     * @parameter default-value="false" expression="${gwt.draftCompile}"
     */
    private boolean draftCompile;

    /**
     * The directory into which extra, non-deployed files will be written.
     *
     * @parameter default-value="${project.build.directory}/extra"
     */
    private File extra;

    /**
     * The temp directory is used for temporary compiled files (defaults is system temp directory).
     *
     * @parameter
     */
    private File workDir;

    /**
     * add -extra parameter to the compiler command line
     * <p>
     * Can be set from command line using '-Dgwt.extraParam=true'.
     * </p>
     * @parameter default-value="false" expression="${gwt.extraParam}"
     * @since 2.1.0-1
     */
    private boolean extraParam;

    /**
     * add -compileReport parameter to the compiler command line
     * <p>
     * Can be set from command line using '-Dgwt.compiler.compileReport=true'.
     * </p>
     * @parameter default-value="false" expression="${gwt.compiler.compileReport}"
     * @since 2.1.0-1
     */
    private boolean compileReport;

    /**
     * add -optimize parameter to the compiler command line the value must be between 0 and 9
     * by default -1 so no arg to the compiler
     * <p>
     * Can be set from command line using '-Dgwt.compiler.optimizationLevel=n'.
     * </p>
     * @parameter default-value="-1" expression="${gwt.compiler.optimizationLevel}"
     * @since 2.1.0-1
     */
    private int optimizationLevel;

    /**
     * add -XsoycDetailed parameter to the compiler command line
     * <p>
     * Can be set from command line using '-Dgwt.compiler.soycDetailed=true'.
     * </p>
     * @parameter default-value="false" expression="${gwt.compiler.soycDetailed}"
     * @since 2.1.0-1
     */
    private boolean soycDetailed;

    /**
     * add -strict parameter to the compiler command line
     * 
     * <p>
     * Can be set from command line using '-Dgwt.compiler.strict=true'.
     * </p>
     * @parameter default-value="false" expression="${gwt.compiler.strict}"
     * @since 2.1.0-1
     */
    private boolean strict;

    public void doExecute() throws MojoExecutionException, MojoFailureException {
        if (skip || "pom".equals(getProject().getPackaging())) {
            getLog().info("GWT compilation is skipped");
            return;
        }

        if (!this.getOutputDirectory().exists()) {
            this.getOutputDirectory().mkdirs();
        }

        compile(getModules());
    }

    private void compile(String[] modules) throws MojoExecutionException {
        boolean upToDate = true;

        JavaCommand cmd = new JavaCommand("com.google.gwt.dev.Compiler");
        if (gwtSdkFirstInClasspath) {
            cmd.withinClasspath(getGwtUserJar()).withinClasspath(getGwtDevJar());
        }
        cmd.withinScope(Artifact.SCOPE_COMPILE);

        if (!gwtSdkFirstInClasspath) {
            cmd.withinClasspath(getGwtUserJar()).withinClasspath(getGwtDevJar());
        }

        cmd.arg("-gen", getGen().getAbsolutePath()).arg("-logLevel", getLogLevel()).arg("-style", getStyle())
                .arg("-war", getOutputDirectory().getAbsolutePath())
                .arg("-localWorkers", String.valueOf(getLocalWorkers()))
                // optional advanced arguments
                .arg(enableAssertions, "-ea").arg(draftCompile, "-draftCompile").arg(validateOnly, "-validateOnly")
                .arg(treeLogger, "-treeLogger").arg(disableClassMetadata, "-XdisableClassMetadata")
                .arg(disableCastChecking, "-XdisableCastChecking").arg(strict, "-strict")
                .arg(soycDetailed, "-XsoycDetailed");

        if (optimizationLevel >= 0) {
            cmd.arg("-optimize").arg(Integer.toString(optimizationLevel));
        }

        if (extraParam || compileReport) {
            getLog().debug("create extra directory ");
            if (!extra.exists()) {
                extra.mkdirs();
            }
            cmd.arg("-extra").arg(extra.getAbsolutePath());
        } else {
            getLog().debug("NOT create extra directory ");
        }

        if (compileReport) {
            cmd.arg("-compileReport");
        }

        addCompileSourceArtifacts(cmd);

        if (workDir != null) {
            cmd.arg("-workDir").arg(String.valueOf(workDir));
        }

        for (String target : modules) {
            if (!compilationRequired(target, getOutputDirectory())) {
                continue;
            }
            cmd.arg(target);
            upToDate = false;
        }
        if (!upToDate) {
            cmd.execute();
        }
    }

    private int getLocalWorkers() {
        if (localWorkers > 0) {
            return localWorkers;
        }
        // workaround to GWT issue 4031 whith IBM JDK
        // @see http://code.google.com/p/google-web-toolkit/issues/detail?id=4031
        if (System.getProperty("java.vendor").startsWith("IBM")) {
            StringBuilder sb = new StringBuilder("Build is using IBM JDK, localWorkers set to 1 as a workaround");
            sb.append(SystemUtils.LINE_SEPARATOR);
            sb.append("see http://code.google.com/p/google-web-toolkit/issues/detail?id=4031");
            getLog().info(sb.toString());
            return 1;
        }
        return Runtime.getRuntime().availableProcessors();
    }

    /**
     * Try to find out, if there are stale sources. If aren't some, we don't have to compile... ...this heuristic
     * doesn't take into account, that there could be updated dependencies. But for this case, as 'clean compile' could
     * be executed which would force a compilation.
     *
     * @param module Name of the GWT module to compile
     * @param output Output path
     * @return true if compilation is required (i.e. stale sources are found)
     * @throws MojoExecutionException When sources scanning fails
     * @author Alexander Gordt
     */
    private boolean compilationRequired(String module, File output) throws MojoExecutionException {
        try {
            GwtModule gwtModule = readModule(module);
            if (gwtModule.getEntryPoints().size() == 0) {
                getLog().debug(gwtModule.getName() + " has no EntryPoint - compilation skipped");
                // No entry-point, this is an utility module : compiling this one will fail
                // with '[ERROR] Module has no entry points defined'
                return false;
            }

            if (force) {
                return true;
            }

            String modulePath = gwtModule.getPath();
            String outputTarget = modulePath + "/" + modulePath + ".nocache.js";

            // Require compilation if no js file present in target.
            if (!new File(output, outputTarget).exists()) {
                return true;
            }

            // js file allreay exists, but may not be up-to-date with project source files
            SingleTargetSourceMapping singleTargetMapping = new SingleTargetSourceMapping(".java", outputTarget);
            StaleSourceScanner scanner = new StaleSourceScanner();
            scanner.addSourceMapping(singleTargetMapping);

            SingleTargetSourceMapping gwtModuleMapping = new SingleTargetSourceMapping(".gwt.xml", outputTarget);
            scanner.addSourceMapping(gwtModuleMapping);

            SingleTargetSourceMapping uiBinderMapping = new SingleTargetSourceMapping(".ui.xml", outputTarget);
            scanner.addSourceMapping(uiBinderMapping);

            Collection<File> compileSourceRoots = new HashSet<File>();
            classpathBuilder.addSourcesWithActiveProjects(getProject(), compileSourceRoots, SCOPE_COMPILE);
            classpathBuilder.addResourcesWithActiveProjects(getProject(), compileSourceRoots, SCOPE_COMPILE);
            for (File sourceRoot : compileSourceRoots) {
                if (!sourceRoot.isDirectory()) {
                    continue;
                }
                try {
                    if (!scanner.getIncludedSources(sourceRoot, output).isEmpty()) {
                        getLog().debug("found stale source in " + sourceRoot + " compared with " + output);
                        return true;
                    }
                } catch (InclusionScanException e) {
                    throw new MojoExecutionException(
                            "Error scanning source root: \'" + sourceRoot + "\' " + "for stale files to recompile.",
                            e);
                }
            }
            getLog().info(module + " is up to date. GWT compilation skipped");
            return false;
        } catch (GwtModuleReaderException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }
}