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

org.nuiton.jaxx.plugin.GenerateMojo Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * JAXX :: Maven plugin
 * %%
 * Copyright (C) 2008 - 2017 CodeLutin
 * %%
 * This program 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 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.jaxx.plugin;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.nuiton.i18n.I18n;
import org.nuiton.io.MirroredFileUpdater;
import org.nuiton.jaxx.compiler.CompiledObjectDecorator;
import org.nuiton.jaxx.compiler.CompilerConfiguration;
import org.nuiton.jaxx.compiler.I18nHelper;
import org.nuiton.jaxx.compiler.JAXXCompiler;
import org.nuiton.jaxx.compiler.JAXXEngine;
import org.nuiton.jaxx.compiler.JAXXFactory;
import org.nuiton.jaxx.compiler.beans.BeanInfoUtil;
import org.nuiton.jaxx.compiler.binding.DataBindingHelper;
import org.nuiton.jaxx.compiler.finalizers.JAXXCompilerFinalizer;
import org.nuiton.jaxx.compiler.spi.DefaultInitializer;
import org.nuiton.jaxx.compiler.spi.Initializer;
import org.nuiton.jaxx.runtime.JAXXContext;
import org.nuiton.jaxx.runtime.JAXXObject;
import org.nuiton.jaxx.runtime.spi.UIHandler;
import org.nuiton.jaxx.runtime.swing.help.JAXXHelpBroker;
import org.nuiton.jaxx.validator.swing.SwingValidator;
import org.nuiton.plugin.PluginHelper;

import java.beans.Introspector;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Generates some java code from jaxx files.
 *
 * @author Tony Chemit - [email protected]
 */
@Mojo(name = "generate", defaultPhase = LifecyclePhase.PROCESS_SOURCES,
        requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true)
public class GenerateMojo extends AbstractJaxxMojo implements CompilerConfiguration {

    /**
     * Directory where jaxx files are located.
     */
    @Parameter(property = "jaxx.src", defaultValue = "${basedir}/src/main/java")
    protected File src;

    /**
     * Where to generate java files.
     */
    @Parameter(property = "jaxx.outJava", defaultValue = "${basedir}/target/generated-sources/java")
    protected File outJava;

    /**
     * To filter file to treat.
     */
    @Parameter(property = "jaxx.includes")
    protected String[] includes;

    /**
     * To filter files to NOt treat.
     */
    @Parameter(property = "jaxx.excludes")
    protected String[] excludes;

    /**
     * FQN of compiler to use (by default swing one).
     */
    @Parameter(property = "jaxx.compilerFQN", defaultValue = "org.nuiton.jaxx.compiler.JAXXCompiler", required = true)
    protected String compilerFQN;

    /**
     * The name of implementation of {@link JAXXContext}to be used on {@link JAXXObject}.
     *
     * Must not be abstract.
     */
    @Parameter(property = "jaxx.jaxxContextFQN", defaultValue = "org.nuiton.jaxx.runtime.context.DefaultJAXXContext", required = true)
    protected String jaxxContextFQN;

    /**
     * The FQN of the ui to use for error notification.
     *
     * If not given, will use the one defined in validator
     */
    @Parameter(property = "jaxx.defaultErrorUIFQN", defaultValue = "org.nuiton.jaxx.validator.swing.ui.ImageValidationUI")
    protected String defaultErrorUIFQN;

    /**
     * The FQN of the ui to use for error notification.
     *
     * If not given, will use the one defined in validator
     *
     * @see CompiledObjectDecorator
     */
    @Parameter(property = "jaxx.defaultDecoratorFQN", defaultValue = "org.nuiton.jaxx.compiler.decorators.DefaultCompiledObjectDecorator")
    protected String defaultDecoratorFQN;

    /**
     * Flag to include in compiler classpath the java sources directories (src
     * and outJava).
     *
     * By default, false.
     */
    @Parameter(property = "jaxx.addSourcesToClassPath", defaultValue = "true")
    protected boolean addSourcesToClassPath;

    /**
     * Flag to include in compiler classpath the java resources directories (src
     * and outJava).
     *
     * By default, false.
     *
     * @since 1.6.0
     */
    @Parameter(property = "jaxx.addResourcesToClassPath", defaultValue = "false")
    protected boolean addResourcesToClassPath;

    /**
     * Flag to include in compiler classpath the compile class-path (can only be
     * used in a test phase).
     *
     * By default, false.
     *
     * @since 1.6.0
     */
    @Parameter(property = "jaxx.addCompileClassPath", defaultValue = "false")
    protected boolean addCompileClassPath;

    /**
     * Flag to include in compiler classpath the project compile classpath.
     *
     * By default, false.
     */
    @Parameter(property = "jaxx.addProjectClassPath", defaultValue = "true")
    protected boolean addProjectClassPath;

    /**
     * A flag to mark the mojo to be used in a test phase. This will permits to
     * add generated sources in test compile roots.
     *
     * @since 1.6.0
     */
    @Parameter(property = "jaxx.testPhase", defaultValue = "false")
    protected boolean testPhase;

    /**
     * To make compiler i18nable, says add the {@link I18n#t(String, Object...)}
     * method invocation on {@link I18nHelper#I18N_ATTRIBUTES} attributes.
     *
     * @see I18nHelper
     */
    @Parameter(property = "jaxx.i18nable", defaultValue = "true")
    protected boolean i18nable;

    /**
     * To optimize generated code.
     */
    @Parameter(property = "jaxx.optimize", defaultValue = "false")
    protected boolean optimize;

    /**
     * To let jaxx recurses in css when a JAXX Object auto import css files
     * for a jaxx file.
     *
     * Warning: This option will be removed in version 3.0 or at least
     * default value will become {@code false}.
     *
     * @since 2.0.2
     */
    @Parameter(property = "jaxx.autoRecurseInCss", defaultValue = "false")
    protected boolean autoRecurseInCss;

    /**
     * Flag to add logger to each generated jaxx file.
     *
     * By default, always add it.
     */
    @Parameter(property = "jaxx.addLogger", defaultValue = "true")
    protected boolean addLogger;

    /**
     * Flag to keep compilers after the generate operation (usefull for tests.
     *
     * By default, always reset.
     */
    @Parameter(property = "jaxx.resetAfterCompile", defaultValue = "true")
    protected boolean resetAfterCompile;

    /**
     * Extra path to be added in {@link Introspector#setBeanInfoSearchPath(String[])}.
     *
     * add beanInfoSearchPath to be registred by {@link BeanInfoUtil#addJaxxBeanInfoPath(String...)}
     *
     * and then will be use by {@link DefaultInitializer#initialize()}.
     *
     *
     * This permit to use real beanInfo of imported graphic libraries.
     */
    @Parameter(property = "jaxx.beanInfoSearchPath")
    protected String[] beanInfoSearchPath;

    /**
     * List of fqn of class toimport for all generated jaxx files.
     */
    @Parameter(property = "jaxx.extraImportList")
    protected String extraImportList;

    /**
     * A flag to use UIManager to retreave icons.
     */
    @Parameter(property = "jaxx.useUIManagerForIcon", defaultValue = "true")
    protected boolean useUIManagerForIcon;

    /**
     * flag to activate profile mode.
     *
     * By default, not active.
     */
    @Parameter(property = "jaxx.profile", defaultValue = "false")
    protected boolean profile;

    /**
     * To show detected bindings.
     *
     * By default, do not show them.
     *
     * @since 2.0.0
     */
    @Parameter(property = "jaxx.showBinding", defaultValue = "false")
    protected boolean showBinding;

    /**
     * the FQN of help broker
     *
     * By default, use the JAXX implementation {@link JAXXHelpBroker}.
     *
     * @since 1.3
     */
    @Parameter(property = "jaxx.helpBrokerFQN", defaultValue = "org.nuiton.jaxx.runtime.swing.help.JAXXHelpBroker")
    protected String helpBrokerFQN;

    /**
     * the FQN of validator factory.
     *
     * By default, use the JAXX implementation {@link SwingValidator}.
     *
     * @since 2.6
     */
    @Parameter(property = "jaxx.validatorFactoryFQN", defaultValue = "org.nuiton.jaxx.validator.swing.SwingValidator")
    protected String validatorFactoryFQN;

    /**
     * To trace class descriptor loading.
     *
     * By default, do not trace it.
     *
     * @since 2.4
     */
    @Parameter(property = "jaxx.showClassDescriptorLoading", defaultValue = "false")
    private boolean showClassDescriptorLoading;

    /**
     * For each jaxx file, try to add a {@link UIHandler} on it.
     *
     * The fqn of the handler must be jaxxFileName{@code Handler}.
     *
     * @since 2.6
     */
    @Parameter(property = "jaxx.addAutoHandlerUI", defaultValue = "true")
    private boolean addAutoHandlerUI;

    /**
     * For each jaxx file, generate the rules in the css files for the ids and style classes which have not been defined.
     *
     * @since 2.29
     */
    @Parameter(property = "jaxx.generateMissingIdsInCss", defaultValue = "false")
    private boolean generateMissingIdsAndStyleClassesInCss;

    /**
     * A optional common css to inject in all jaxx files.
     *
     * @since 2.13
     */
    @Parameter(property = "jaxx.commonCss")
    private File commonCss;

    /**
     * The extension of css files.
     *
     * @since 2.28
     */
    @Parameter(property = "jaxx.cssExtension", defaultValue = DEFAULT_CSS_EXTENSION)
    private String cssExtension;

    /**
     * Decorators available in engine.
     *
     * @since 2.0.2
     */
    @Component(role = CompiledObjectDecorator.class)
    protected Map decorators;

    /**
     * Finalizers available in engine.
     *
     * @since 2.0.2
     */
    @Component(role = JAXXCompilerFinalizer.class)
    protected Map finalizers;

    /**
     * Initializers available to init engine.
     *
     * @since 2.0.2
     */
    @Component(role = Initializer.class)
    protected Map initializers;

    /** detected jaxx files in {@link #init()} method */
    protected String[] files;

    /**
     * file updater used to detect jaxx files.
     *
     * Note: if {@link #verbose} flag is on, will ne be used
     */
    protected MirroredFileUpdater updater;

    /** type of error ui class (in validation) to use */
    private Class defaultErrorUIClass;

    /** type of {@link CompiledObjectDecorator} to use */
    private Class defaultDecoratorClass;

    /** type of {@link JAXXContext} to use */
    private Class jaxxContextClass;

    /** type of compiler to use */
    private Class compilerClass;

    /** extra imports to always add in each generated java file */
    private String[] extraImports;

    /** internal state to known if a files has to be generated */
    private boolean nofiles;

    /** customized classloader to use in engine */
    protected ClassLoader cl;

    /** JAXX engine */
    private JAXXEngine engine;

    @SuppressWarnings("unchecked")
    @Override
    public void init() throws Exception {

        if (getLog().isDebugEnabled()) {
            // if debug is on, then verbose also
            setVerbose(true);
        }
        fixCompileSourceRoots();

        if (cssExtension == null) {
            cssExtension = DEFAULT_CSS_EXTENSION;
        }

        if (includes == null || includes.length == 0) {
            // use default includes
            includes = new String[]{"**/*.jaxx", "**/*." + cssExtension};
        }

        updater = new JaxxFileUpdater(cssExtension, src, outJava);

        Map result = new HashMap<>();
        getFilesToTreateForRoots(
                includes,
                excludes,
                Collections.singletonList(src.getAbsolutePath()),
                result,
                isForce() ? null : updater);

        files = result.get(src);

        // Evolution #435: Regenerates jaxx files when his css file is modified
        // filter css and jaxx files to obtain only jaxx files
        // if a css is modified, try to find the corresponding jaxx files
        if (files != null && files.length > 0) {
            Set filterFiles = new HashSet<>(files.length);
            int cssExtensionLength = cssExtension.length() + 1;
            for (String path : files) {
                if (path.endsWith("." + cssExtension)) {
                    // take the jaxx file
                    String jaxxFilePath = path.substring(0, path.length() - cssExtensionLength) + ".jaxx";
                    File f = new File(src, jaxxFilePath);
                    if (f.exists()) {
                        if (isVerbose()) {
                            getLog().info("will treate jaxx file from css " +
                                                  f);
                        }
                        filterFiles.add(jaxxFilePath);
                    }
                    continue;
                }
                if (path.endsWith(".jaxx")) {
                    filterFiles.add(path);
                }
            }
            files = filterFiles.toArray(new String[filterFiles.size()]);
        }

        nofiles = files == null || files.length == 0;
        if (nofiles) {
            if (getLog().isDebugEnabled()) {
                getLog().debug("No file to treate.");
            }
            return;
        }

        cl = initClassLoader(getProject(),
                             src,
                             addSourcesToClassPath,
                             testPhase,
                             addResourcesToClassPath,
                             addCompileClassPath,
                             addProjectClassPath);

        Thread.currentThread().setContextClassLoader(cl);

        compilerClass = (Class)
                Class.forName(compilerFQN, false, cl);
        defaultDecoratorClass = (Class)
                Class.forName(defaultDecoratorFQN, false, cl);
        jaxxContextClass = (Class)
                Class.forName(jaxxContextFQN, false, cl);
        if (!JAXXContext.class.isAssignableFrom(jaxxContextClass)) {
            throw new MojoExecutionException(
                    "jaxxContextFQN must be an implementation of " +
                            JAXXContext.class + " but was : " + jaxxContextClass);
        }
//        validatorClass = Class.forName(validatorFQN, false, cl);

        if (defaultErrorUIFQN != null && !defaultErrorUIFQN.trim().isEmpty()) {
            defaultErrorUIClass = Class.forName(defaultErrorUIFQN, false, cl);
        }

        if (beanInfoSearchPath != null && beanInfoSearchPath.length > 0) {
            // register extra path
            BeanInfoUtil.addJaxxBeanInfoPath(beanInfoSearchPath);
        }

        createDirectoryIfNecessary(getTargetDirectory());

        // compute extra imports (can not use java classes since some of
        // imports can not be still compiled)
        if (extraImportList != null && !extraImportList.isEmpty()) {
            String[] imports = extraImportList.split(",");
            int i = 0;
            for (String importS : imports) {
                imports[i++] = importS.trim();
            }
            if (isVerbose()) {
                getLog().info("extra imports " + Arrays.toString(imports));
            }
            extraImports = imports;
        }

        if (isVerbose()) {
//            getLog().info(toString());
            getLog().info("includes : " + Arrays.toString(includes));
            for (String file : files) {
                getLog().info("will parse " + file);
            }
        }
    }

    @Override
    protected boolean checkSkip() {
        if (nofiles) {
            getLog().info("Nothing to generate - all files are up to date.");
            return false;
        }
        return true;
    }

    @Override
    public void doAction() throws Exception {

        getLog().info("Detects " + files.length + " modified jaxx file(s). ");

        if (showBinding) {
            DataBindingHelper.SHOW_LOG = showBinding;
        }
        try {
            long t0 = System.nanoTime();

            // register configuration to factory
            JAXXFactory.setConfiguration(this);

            // create new engine
            engine = JAXXFactory.newEngine(src, files);

            //FIXME-TC20100502 remove this managment by -1 for error!
            // run engine
            int nbFiles = engine.run();

            // report engine results (errors, warnings,...)
            report(engine);

            if (nbFiles == -1) {
                throw new MojoExecutionException(
                        "Aborting due to errors reported by jaxxc");
            }
            String delay = PluginHelper.convertTime(System.nanoTime() - t0);
            getLog().info("Generated " + nbFiles + " file(s) in " + delay);
        } finally {
            DataBindingHelper.SHOW_LOG = false;
        }
    }

    @Override
    public File getTargetDirectory() {
        return outJava;
    }

    @Override
    public void setTargetDirectory(File targetDirectory) {
        outJava = targetDirectory;
    }

    @Override
    public boolean getOptimize() {
        return optimize;
    }

    @Override
    public boolean isAutoRecurseInCss() {
        return autoRecurseInCss;
    }

    @Override
    public boolean isI18nable() {
        return i18nable;
    }

    @Override
    public boolean isUseUIManagerForIcon() {
        return useUIManagerForIcon;
    }

    @Override
    public boolean isAddLogger() {
        return addLogger;
    }

    @Override
    public boolean isShowClassDescriptorLoading() {
        return showClassDescriptorLoading;
    }

    @Override
    public boolean isAddAutoHandlerUI() {
        return addAutoHandlerUI;
    }

    @Override
    public void setAddAutoHandlerUI(boolean addAutoHandlerUI) {
        this.addAutoHandlerUI = addAutoHandlerUI;
    }

    @Override
    public boolean isGenerateMissingIdsAndStyleClassesInCss() {
        return generateMissingIdsAndStyleClassesInCss;
    }

    @Override
    public void setGenerateMissingIdsAndStyleClassesInCss(boolean generateMissingIdsAndStyleClassesInCss) {
        this.generateMissingIdsAndStyleClassesInCss = generateMissingIdsAndStyleClassesInCss;
    }

    @Override
    public Class getJaxxContextClass() {
        return jaxxContextClass;
    }

    @Override
    public String[] getExtraImports() {
        return extraImports;
    }

    @Override
    public boolean isResetAfterCompile() {
        return resetAfterCompile;
    }

    @Override
    public boolean isOptimize() {
        return optimize;
    }

    @Override
    public Class getDefaultErrorUI() {
        return defaultErrorUIClass;
    }

    @Override
    public ClassLoader getClassLoader() {
        return cl;
    }

    @Override
    public Class getCompilerClass() {
        return compilerClass;
    }

    @Override
    public Class getDefaultDecoratorClass() {
        return defaultDecoratorClass;
    }

    @Override
    public boolean isProfile() {
        return profile;
    }

    @Override
    public boolean isGenerateHelp() {
        return generateHelp;
    }

    @Override
    public String getHelpBrokerFQN() {
        return helpBrokerFQN;
    }

    @Override
    public String getValidatorFactoryFQN() {
        return validatorFactoryFQN;
    }

    @Override
    public Map getDecorators() {
        return decorators;
    }

    @Override
    public Map getFinalizers() {
        return finalizers;
    }

    @Override
    public Map getInitializers() {
        return initializers;
    }

    @Override
    public File getCommonCss() {
        return commonCss;
    }

    @Override
    public String getCssExtension() {
        return cssExtension;
    }

    public JAXXEngine getEngine() {
        return engine;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(
                this, ToStringStyle.MULTI_LINE_STYLE);
    }

    protected void fixCompileSourceRoots() {
        //FIXME TC20091222 : why this test ? should always have a project ?
        // even in tests...
        if (getProject() == null) {
            // no project defined, can not fix anything
            // this case could appear if we wanted to do some tests of the plugin
            return;
        }

        if (testPhase) {
            addTestCompileSourceRoots(getTargetDirectory());
        } else {
            addCompileSourceRoots(getTargetDirectory());
        }
    }

    protected void report(JAXXEngine engine) {
        List warnings = engine.getWarnings();
        if (!warnings.isEmpty()) {
            StringBuilder buffer = new StringBuilder(
                    "JAXX detects " +
                            (warnings.size() == 1 ? "1 warning" :
                                    warnings.size() + " warnings"));
            buffer.append(" :");
            for (String s : warnings) {
                buffer.append("\n").append(s);
            }
            getLog().warn(buffer.toString());
        }
        List errors = engine.getErrors();
        if (!errors.isEmpty()) {
            StringBuilder buffer = new StringBuilder(
                    "JAXX detects " +
                            (errors.size() == 1 ? "1 error" :
                                    errors.size() + " errors"));
            buffer.append(" :");
            for (String s : errors) {
                buffer.append("\n").append(s);
            }
            getLog().error(buffer.toString());
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy