Package org.spiffyui.maven.plugins

Source Code of org.spiffyui.maven.plugins.GwtCompileMojo$ClassBuilder

/*******************************************************************************
*
* Copyright 2011 Spiffy UI Team  
*
* 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.spiffyui.maven.plugins;

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

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.lang.SystemUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.cli.CommandLineUtils;

/**
* Invokes the GWTCompiler for the project source
*
* @goal gwt-compile
* @phase compile
*/
public class GwtCompileMojo extends AbstractMojo
{
    /**
     * {@link MavenProject} to process.
     *
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    private MavenProject project;

    /**
     * @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
     * permutations. 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;

    /**
     * The source directories containing the sources to be compiled.
     *
     * @parameter default-value="${project.compileSourceRoots}"
     * @required
     * @readonly
     */
    private List<String> compileSourceRoots;

    /**
     * The source directory
     *
     * @parameter default-value="src/main/resources"
     * @required
     */
    private File resources;

    /**
     * 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}"
     */
    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}"
     */
    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}"
     */
    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}"
     */
    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}"
     */
    private boolean strict;

    /**
     * Location on filesystem where GWT will write generated content for review (-gen option to GWTCompiler).
     * <p>
     * Can be set from command line using '-Dgwt.gen=...'
     * </p>
     * @parameter default-value="${project.build.directory}/.generated" expression="${gwt.gen}"
     */
    private File gen;

    /**
     * GWT logging level (-logLevel ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL).
     * <p>
     * Can be set from command line using '-Dgwt.logLevel=...'
     * </p>
     * @parameter default-value="INFO" expression="${gwt.logLevel}"
     */
    private String logLevel;

    /**
     * GWT JavaScript compiler output style (-style OBF[USCATED], PRETTY, or DETAILED).
     * <p>
     * Can be set from command line using '-Dgwt.style=...'
     * </p>
     * @parameter default-value="OBF" expression="${gwt.style}"
     */
    private String style;

    /**
     * The output directory
     *
     * @parameter expression="${spiffyui.www}"
     * @required
     */
    private File outputDirectory;
   
    /**
     * Extra JVM arguments that are passed to the GWT-Maven generated scripts
     * (for compiler, shell, etc - typically use -Xmx512m here, or -XstartOnFirstThread, etc)
     *
     * @parameter expression="${gwt.extraJvmArgs}" default-value="-Xmx512m"
     */
    private String extraJvmArgs;
   
    /**
     * @parameter default-value="${spiffyui.gwt.module.name}"
     * @required
     * @readonly
     */
    private String gwtModuleName;

    /**
     * @parameter default-value="${spiffyui.gwt.module.path}"
     * @required
     * @readonly
     */
    private File gwtModulePath;
   
    private final Set<String> compileScope =
           new HashSet<String>(Arrays.asList(SCOPE_COMPILE, SCOPE_PROVIDED, SCOPE_SYSTEM));
    /**
     * Convenience class that makes it easier to build a string of arguments for
     * passing to the compiler
     *
     */
    protected class ClassBuilder
    {
        private List<String> m_classes = new ArrayList<String>();
       
        ClassBuilder(MavenProject proj)
        {
            Set<Artifact> artifacts = proj.getDependencyArtifacts();
           
            if (artifacts != null) {
                for (Artifact artifact : artifacts) {
                    if (compileScope.contains(artifact.getScope())) {
                        /*
                         Some plugins add artifacts without associated JAR
                         files in that case the file is null and we don't
                         need to worry about adding it to the classpath.
                         */
                        if (artifact.getFile() != null) {
                            add(artifact.getFile().getAbsolutePath());
                        }
                    }
                }
            }
        }
       
        ClassBuilder add(String arg)
        {
            m_classes.add(arg);
            return this;
        }

        @Override
        public String toString()
        {       
            return m_classes.toString()
            .replace(", ", File.pathSeparator)
            .replace("[", "")
            .replace("]", "");
        }            
    }
   
    @Override
    public void execute()
        throws MojoExecutionException,
            MojoFailureException
    {
        Properties p = project.getProperties();
       
        if (skip || "pom".equals(project.getPackaging())) {
            getLog().debug("GWT compilation is skipped");
            return;
        }

        if (!outputDirectory.exists()) {
            outputDirectory.mkdirs();
        } else if (!force) {
            String name = gwtModuleName;
            if (name.endsWith(InitializeMojo.SPIFFY_TMP_SUFFIX)) {
                name = name.substring(0, name.length() - InitializeMojo.SPIFFY_TMP_SUFFIX.length());
            }

            if (Math.max(getNewestModifiedTime(resources, -1), getNewestModifiedTime(new File(compileSourceRoots.get(0)), -1)) <
                getOldestModifiedTime(new File(outputDirectory, name), -1)) {
                /*
                 Then the GWT build is up to date and we can skip it
                 */
                getLog().info("GWT files are up to date. Skipping GWT build.");
                return;
            }
        }
       
        CommandLine cmd = new CommandLine("java");
        ClassBuilder cb = new ClassBuilder(project);
       
        cb.add(p.getProperty("spiffyui.generated-source"));
        cb.add(resources.getAbsolutePath());

        for (String sourceRoot : compileSourceRoots) {
            cb.add(sourceRoot);
        }
       
        cmd.addArgument("-cp").addArgument(cb.toString())
            .addArgument(extraJvmArgs)
            .addArgument("com.google.gwt.dev.Compiler")
            .addArgument("-gen").addArgument(gen.getAbsolutePath())
            .addArgument("-logLevel").addArgument(logLevel)
            .addArgument("-style").addArgument(style)
            .addArgument("-war").addArgument(outputDirectory.getAbsolutePath())
            .addArgument("-localWorkers").addArgument(String.valueOf(getLocalWorkers()));
       
        // optional advanced arguments
        if (enableAssertions) {
            cmd.addArgument("-ea");
        }
       
        if (draftCompile) {
            cmd.addArgument("-draftCompile");
        }
        if (validateOnly) {
            cmd.addArgument("-validateOnly");
        }
       
        if (treeLogger) {
            cmd.addArgument("-treeLogger");
        }
       
        if (disableClassMetadata) {
            cmd.addArgument("-XdisableClassMetadata");
        }
       
        if (disableCastChecking) {
            cmd.addArgument("-XdisableCastChecking");
        }
       
        if (strict) {
            cmd.addArgument("-strict");
        }
       
        if (soycDetailed) {
            cmd.addArgument("-XsoycDetailed");
        }
        if (optimizationLevel >= 0) {
            cmd.addArgument("-optimize").addArgument(Integer.toString(optimizationLevel));
        }

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

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

        if (workDir != null) {
            cmd.addArgument("-workDir").addArgument(String.valueOf(workDir));
        }
       
        cmd.addArgument(gwtModuleName);
               
        try {
            DefaultExecutor executor = new DefaultExecutor();

            getLog().debug("Exec: " + cmd.toString());

            int ret = executor.execute(cmd, CommandLineUtils.getSystemEnvVars());
            if (ret != 0) {
                throw new MojoExecutionException("Exec failed: " + Integer.toString(ret));
            }
        } catch (IOException e) {
            throw new MojoExecutionException(e.getMessage());
        }
        moveJSDir();
    }
   
    private static long getOldestModifiedTime(File dir, long current)
    {
        if (dir == null || !dir.exists()) {
            return current;
        }
       
        for (File f : dir.listFiles()) {
            if (f.isDirectory()) {
                current = Math.min(getOldestModifiedTime(f, current), current);
            } else if (f.getName().endsWith(".cache.html")) {
                if (current == -1) {
                    current = f.lastModified();
                }
               
                current = Math.min(current, f.lastModified());
            }
        }
       
        return current;
    }
   
    private static long getNewestModifiedTime(File dir, long current)
    {
        for (File f : dir.listFiles()) {
            if (current == -1) {
                current = f.lastModified();
            }
           
            if (f.isDirectory()) {
                current = Math.max(getNewestModifiedTime(f, current), current);
            } else {
                current = Math.max(current, f.lastModified());
            }
        }
       
        return current;
    }
   
    /**
     * By default GWT puts everything in a directory with the same name as the module. 
     * This causes a problem because we need to find the JavaScript files as runtime so
     * we can determine the supported locales and there is no good way to find the module
     * name from the server-side at runtime. 
     *
     * The solution is that we move the localized JavaScript files to the root of the WAR
     * so we can find them at runtime and figure out the locale that way.  This all feels
     * a little hacky, but I can't think of a better solution.
     *
     * @param outputDirectory
     *                the GWT compiler output directory
     * @param targets the list of modules that were compiled
     *
     * @exception IOException
     */
    private void moveJSDir()
    {
        File jslib = new File(gwtModulePath, "js" + File.separator + "lib" + File.separator + "i18n");
        if (jslib.exists()) {
            File newJslib = new File(outputDirectory, "js" + File.separator + "lib");
            newJslib.mkdirs();
            jslib.renameTo(new File(newJslib, "i18n"));
        }
    }

    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();
    }

}
TOP

Related Classes of org.spiffyui.maven.plugins.GwtCompileMojo$ClassBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.