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

org.nuiton.i18n.plugin.parser.AbstractI18nParserMojo Maven / Gradle / Ivy

Go to download

Maven plugin to deal with i18n stuff in a project, mainly base on the nuiton-i18n api (but not only).

There is a newer version: 4.2
Show newest version
/*
 * #%L
 * I18n :: Maven Plugin
 * 
 * $Id$
 * $HeadURL$
 * %%
 * Copyright (C) 2007 - 2010 CodeLutin, Tony Chemit
 * %%
 * 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.i18n.plugin.parser;

import org.apache.maven.plugins.annotations.Parameter;
import org.nuiton.i18n.plugin.AbstractI18nGenerateMojo;
import org.nuiton.i18n.plugin.I18nUtil;
import org.nuiton.io.FileUpdater;
import org.nuiton.io.SortedProperties;
import org.nuiton.plugin.PluginHelper;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Abstract implementation for parsing goal.
 *
 * @author Tony Chemit - [email protected]
 */
public abstract class AbstractI18nParserMojo extends AbstractI18nGenerateMojo implements I18nParserConfiguration {

    /** @return the outGetter to use for the instance (java.getter,...) */
    protected abstract String getOutGetter();

    /** @return the default includes to add to directory scanner */
    protected abstract String[] getDefaultIncludes();

    /** @return the default excludes to add to directory scanner */
    protected abstract String[] getDefaultExcludes();

    /** @return the default src directory to use in directory scanner */
    protected abstract File getDefaultBasedir();

    /**
     * @param acceptPattern optional pattern to accept incoming keys
     * @return a new file parser to be used in the parser consumer parserExecutor
     * @since 1.2
     */
    public abstract FileParser newFileParser(Pattern acceptPattern);

    /**
     * @param entry the incoming source entry to attach to the file updater
     * @return a new file updater to detects files to treate
     */
    public abstract FileUpdater newFileUpdater(SourceEntry entry);

    /** Directory where to find project i18n files. */
    @Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true)
    protected File src;

    /**
     * Strict mode to only keep in user i18n detected i18n keys and remove obsolete keys.
     *
     * Note : By default not active. Use this with care since it can
     * delete keys. Moreover if this flag is activated, then all files will be parsed.
     */
    @Parameter(property = "i18n.strictMode", defaultValue = "false")
    protected boolean strictMode;

    /** Build directory (used to know if files in sources are up-to-date). */
    @Parameter(property = "i18n.cp", defaultValue = "${basedir}/target/classes")
    protected File cp;

    /** To treat default entry offered by the mojo. */
    @Parameter(property = "i18n.treateDefaultEntry", defaultValue = "true")
    protected boolean treateDefaultEntry;

    /** Source entries (src+includes+excludes) to process. */
    @Parameter(property = "i18n.entries")
    protected I18nSourceEntry[] entries;

    /**
     * Flag to display touched files while parsing.
     *
     * Note: the value will be always {@code true} if {@link #verbose} is
     * set at {@code true}.
     *
     * @since 0.9
     */
    @Parameter(property = "i18n.showTouchedFiles", defaultValue = "${maven.verbose}")
    protected boolean showTouchedFiles;

    /**
     * Flag to save previous getter in a backup before doing parsing.
     *
     * Note: by default, do not perform backup (but it was here originaly so let
     * it possible...)
     *
     * @since 1.0.2
     */
    @Parameter(property = "i18n.backupGetter", defaultValue = "false")
    protected boolean backupGetter;

    /**
     * To force reparse of all sources.
     *
     * @since 1.2
     */
    @Parameter(property = "i18n.force", defaultValue = "false")
    protected boolean force;

    /**
     * A regex pattern to accept incoming keys.
     *
     * Only incoming keys which match the pattern will be kept.
     *
     * @since 2.5
     */
    @Parameter(property = "i18n.acceptKeyFormat")
    protected String acceptKeyFormat;

    protected Pattern acceptPattern;

    private SortedProperties result;

    protected SortedProperties oldParser;

    protected SortedProperties oldLanguage;

    protected long t0;

    ParserExecutor parserExecutor;

//    @Override
//    public boolean isStrictMode() {
//        return strictMode;
//    }

    public boolean isForce() {
        return force;
    }

    @Override
    public void init() throws Exception {
        super.init();
        t0 = System.nanoTime();
        result = new SortedProperties(encoding);
        oldParser = new SortedProperties(encoding);
        oldLanguage = new SortedProperties(encoding);
        createDirectoryIfNecessary(out);
//        // evenements
//        if (keysModifier) {
//            addParserEvent(KeysModifier.getInstance(
//                    getKeyModifierStart(), getKeyModifierEnd(), encoding));
//        }

        // check there is something to treate
        if ((entries == null || entries.length == 0) && !treateDefaultEntry) {
            // nothing to do
            throw new IllegalStateException(
                    "No entry defined and treateDefaultEntry is false, " +
                    "will skip the goal.");
        }

        if (verbose && entries != null && entries.length > 0) {
            if (getLog().isInfoEnabled()) {

                getLog().info("detected entries : " + entries.length);
                for (SourceEntry e : entries) {
                    getLog().info(e.toString() + ", specific goal ? " +
                                  e.getSpecificGoal());
                }
            }
        }

        if (acceptKeyFormat != null) {
            acceptPattern = Pattern.compile(acceptKeyFormat);
        }

        parserExecutor = new ParserExecutor(this);
    }

    protected boolean onEnterEntry(I18nSourceEntry entry) {
        boolean skip = entry.init(this);
        return skip;
    }

    @Override
    protected void doAction() throws Exception {

        if (!silent && strictMode) {
            getLog().info("config - strictMode is on (all files will be" +
                          " parsed).");
        }
        if (!silent && force) {
            getLog().info("config - force is on (all files will be" +
                          " parsed).");
        }

        // Reprise sur un ancien parsing
        File oldParserFile = getGetterFile(out, getOutGetter(), true);
        File saveFile = getBackupFile(oldParserFile);

        oldParser.load(oldParserFile);
        if (backupGetter) {
            backupFile(oldParserFile);
        }

        // Anciennes cles disponnibles
        //fixme : pourquoi on utilise un bundle precis ? le premier ici,
        // je ne comprends pas
        File oldLanguageFile = I18nUtil.getI18nFile(src, artifactId, locales[0], true);

        oldLanguage.load(oldLanguageFile);

        // Parsing
        if (treateDefaultEntry) {
            addDefaultEntry();
        }

        for (I18nSourceEntry entry : entries) {

            boolean skip = onEnterEntry(entry);

            if (skip) {
                if (!silent && verbose) {
                    getLog().info("skip [" + entry + "] - " + entry.getSkipMessage());
                }
                continue;
            }

            // launch parser for found files
            String[] files = entry.getFiles();

            if (!silent) {
                getLog().info("start entry " + entry.toString());
                getLog().info(files.length + " file(s) to process (among " +
                              entry.getFoudFiles() + " files)");
            }

            for (String file1 : files) {
                String fileName = entry.getBasedir().getAbsolutePath() +
                                  File.separator + file1;
                File file = new File(fileName);
                parserExecutor.addFile(newFileParser(acceptPattern), file);
            }
        }

        if (getLog().isDebugEnabled()) {
            getLog().debug("ask to terminate " + parserExecutor);
        }

        // all files are send to parserExecutor, we ask termination of parserExecutor.
        // this termination treat all sending file before really stop
        parserExecutor.terminatesAndWaits();

        List treadedFiles = parserExecutor.getTreatedFiles();
        List touchedFiles = parserExecutor.getTouchedFiles();

        // Suppression du fichier sauvegarder
        if (!backupGetter) {
            deleteFile(saveFile);
        }

        if (treadedFiles.isEmpty()) {
            if (!silent) {
                getLog().info("Nothing was parsed - all files are up to date.");
            }
        } else {
            if (showTouchedFiles) {
                for (File f : touchedFiles) {
                    getLog().info("touch " + f);
                }
            }
            if (!silent) {
                int i = touchedFiles.size();
                int max = treadedFiles.size();
                getLog().info(getLogEntry(
                        "Parsing is done. [treated file(s) : " + i + '/' +
                        max + "]", max, 0, t0));
            }
            // save getter
            saveGetterFile();
            // add getter
            addGetter();
        }

        parserExecutor.clear();
    }

    @Override
    public boolean isShowTouchedFiles() {
        return showTouchedFiles;
    }

    @Override
    public SortedProperties getResult() {
        return result;
    }

    public boolean isStrictMode() {
        return strictMode;
    }

    /**
     * Add the default entry to entries given in configuration.
     *
     * This is a convinient method to simplify the configuration of the plugin.
     */
    protected void addDefaultEntry() {
        if (verbose) {
            getLog().info("add default entry");
        }
        boolean hasEntries = entries != null && entries.length > 0;
        I18nSourceEntry[] tmp =
                new I18nSourceEntry[hasEntries ? entries.length + 1 : 1];
        if (hasEntries) {
            System.arraycopy(entries, 0, tmp, 0, entries.length);
        }
        tmp[tmp.length - 1] = new I18nSourceEntry();
        entries = tmp;
    }

    /**
     * Save the result in the getter file.
     *
     * @throws IOException if any io pb
     */
    protected void saveGetterFile() throws IOException {
        File getterFile = getGetterFile(out, getOutGetter(), false);
        result.store(getterFile);
    }

    /**
     * Construit une chaine de log formatée.
     *
     * @param msg     le prefix du message
     * @param nbFiles le nombre de fichiers actuellement traités
     * @param time    le time de traitement de ce fichier
     * @param all     le temps de traitement de tous les fichiers
     * @return la chaine de log formatée
     */
    public static String getLogEntry(String msg,
                                     int nbFiles,
                                     long time,
                                     long all) {
        long now = System.nanoTime();
        long delta = now - time;
        String s = msg;
        if (time > 0 && all == 0) {
            s += " (" + PluginHelper.convertTime(delta) + ")";
        }
        if (all > 0) {
            s += "(total time:" + PluginHelper.convertTime(now - all) + ")";
        }
        if (nbFiles > 0) {
            s += " ( ~ " +
                 PluginHelper.convertTime((now - all) / nbFiles) + " / file)";
        }
        return s;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy