r1795 - trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl
Author: tchemit Date: 2010-11-11 11:52:30 +0100 (Thu, 11 Nov 2010) New Revision: 1795 Url: http://nuiton.org/repositories/revision/i18n/1795 Log: Evolution #1026: Introduce parserXml mojo Evolution #1027: Refactor ParserXml*** Evolution #1028: Deprecates parserJavaActionConfig and parserJavaTabConfig mojo Added: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/AbstractParserXmlMojo.java trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlUserMojo.java Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfigMojo.java trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfigMojo.java trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidationMojo.java trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlMojo.java Copied: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/AbstractParserXmlMojo.java (from rev 1789, trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlMojo.java) =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/AbstractParserXmlMojo.java (rev 0) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/AbstractParserXmlMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -0,0 +1,370 @@ +/* + * #%L + * I18n :: Maven Plugin + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2007 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ + +package org.nuiton.i18n.plugin.parser.impl; + +import org.apache.commons.lang.StringUtils; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.logging.Log; +import org.nuiton.i18n.plugin.parser.AbstractFileParser; +import org.nuiton.i18n.plugin.parser.AbstractI18nParserMojo; +import org.nuiton.i18n.plugin.parser.FileParser; +import org.nuiton.i18n.plugin.parser.ParserException; +import org.nuiton.io.SortedProperties; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Abstract xml parser mojo. + * + * @author tchemit <chemit@codelutin.com> + * @author jruchaud <ruchaud@codelutin.com> + * @since 2.0 + */ +public abstract class AbstractParserXmlMojo extends AbstractI18nParserMojo { + + /** Taille du buffer pour les lectures/écritures */ + protected static final int BUFFER_SIZE = 8 * 1024; + + /** available rules to detect i18n keys in xml files. */ + protected String rules; + + /** XPath factory used to detect i18n keys in xml files. */ + protected XPathFactory factory; + + /** Document builder factory to load xml files. */ + protected DocumentBuilderFactory documentBuilderFactory; + + /** + * Extra rules files to use for detecting i18n keys in xml validation files. + * <p/> + * <b>Note : </b> If the {@code coreRulesFile} is not defined, then you must + * fill this parameter. + * + * @parameter + * @since 2.0 + */ + protected String[] userRulesFiles; + + /** + * Defines namespaces mapping if needed. + * <p/> + * Example : + * <pre> + * <namespaces> + * <s>http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd</s> + * </namespaces> + * </pre> + * + * @parameter + * @since 2.0 + */ + protected Map<String, String> namespaces; + + protected abstract String getCoreRuleFile(); + + protected abstract XmlFileParser newXmlFileParser(XPath xpath, + DocumentBuilder builder); + + /** + * Obtain the list of files which define rules to apply. + * + * @return the list of path to rule files to used. + */ + protected List<String> getRulefiles() { + List<String> result = new ArrayList<String>(); + + // load optional core rule file + String s = getCoreRuleFile(); + if (!StringUtils.isEmpty(s)) { + result.add(s); + } + + // load user rile files + String[] userFiles = getUserRuleFiles(); + if (userFiles != null) { + for (String f : userFiles) { + if (!StringUtils.isEmpty(f)) { + result.add(f); + } + } + } + return result; + } + + @Override + public void init() throws Exception { + super.init(); + factory = XPathFactory.newInstance(); + + List<String> files = getRulefiles(); + + if (files.isEmpty()) { + + // no rules file defined + throw new MojoFailureException("No rules files defined, fill the coreRulesFile or userRulesFiles parameters"); + } + + rules = loadRules(files); + + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setValidating(false); + documentBuilderFactory.setCoalescing(false); + documentBuilderFactory.setIgnoringComments(true); + } + + public final String[] getUserRuleFiles() { + return userRulesFiles; + } + + @Override + public final FileParser newFileParser() { + + DocumentBuilder builder; + try { + // never forget this! + builder = documentBuilderFactory.newDocumentBuilder(); + + } catch (ParserConfigurationException ex) { + throw new IllegalStateException( + "could not load DocumentBuilder for reason " + + ex.getMessage(), ex); + } + XPath xpath = factory.newXPath(); + + return newXmlFileParser(xpath, builder); + } + + protected String loadRules(List<String> files) { + + List<String> rules = new ArrayList<String>(); + + boolean verbose = !isSilent() && isVerbose(); + + for (String file : files) { + + getLog().info("Load rules file " + file); + + try { + String fileRules = loadRulesFile(file); + rules.add(fileRules); + + if (verbose) { + getLog().info("Rules for file [" + file + "] : " + fileRules); + } + + } catch (IOException e) { + throw new ParserException(e); + } + } + + String result = StringUtils.join(rules, " | "); + if (verbose) { + getLog().info("Loaded rules : " + result); + } + return result; + } + + protected String loadRulesFile(String fileRules) throws IOException { + File f = new File(fileRules); + + InputStream inputStream; + if (f.exists()) { + + // load from a file + try { + inputStream = new FileInputStream(f); + } catch (FileNotFoundException e) { + throw new ParserException(e); + } + } else { + + // load from classpath + ClassLoader classLoader = getClass().getClassLoader(); + inputStream = classLoader.getResourceAsStream(fileRules); + } + if (inputStream == null) { + throw new ParserException( + "could not found file of rules : " + fileRules); + } + + inputStream = new BufferedInputStream(inputStream); + + try { + // Lecture + String readInputStream; + readInputStream = readInputStream(inputStream); + return readInputStream; + } catch (IOException e) { + throw new ParserException(e); + } finally { + inputStream.close(); + } + } + + /** + * Permet la lecture d'un InputStream et Suppressions. + * + * @param in le flux entrant + * @return le contenu du flux + * @throws IOException si problème de lecture dans flux entrant + */ + private String readInputStream(InputStream in) throws IOException { + StringBuilder sb = new StringBuilder(); + byte[] buffer = new byte[BUFFER_SIZE]; + while (in.read(buffer, 0, BUFFER_SIZE) != -1) { + String tmp = new String(buffer); + sb.append(tmp); + } + in.close(); + // Suppression + String txt = sb.toString().trim(); + + // suppression des commentaires + txt = txt.replaceAll("#.*\n", ""); + + // contruction du xpath avec des ou + txt = txt.replaceAll("\\s+", " | "); + + // suppression des ou de début et de fin + txt = txt.replaceAll("(^ \\| )|( \\| $)", ""); + return txt; + } + + public static abstract class XmlFileParser extends AbstractFileParser { + + private final XPath xpath; + + private final String rules; + + private final DocumentBuilder builder; + + private final Map<String, String> namespaces; + + private final Map<String, String> namespaces2; + + /** + * Fonction d'extraction de la chaine + * + * @param i18nString le clef i18n + * @return la chaine + */ + public abstract String extract(String i18nString); + + public XmlFileParser(Log log, + String encoding, + SortedProperties oldParser, + boolean showTouchedFiles, + String rules, + XPath xpath, + DocumentBuilder builder, Map<String, String> namespaces) { + super(log, encoding, oldParser, showTouchedFiles); + this.xpath = xpath; + this.rules = rules; + this.builder = builder; + + if (namespaces != null && !namespaces.isEmpty()) { + this.namespaces = namespaces; + namespaces2 = new TreeMap<String, String>(); + for (Map.Entry<String, String> e : namespaces.entrySet()) { + namespaces2.put(e.getValue(), e.getKey()); + } + NamespaceContext ctx = new NamespaceContext() { + public String getNamespaceURI(String prefix) { + return XmlFileParser.this.namespaces.get(prefix); +// return getNamespaceForPrefix(prefix, doc); + } + + @Override + public String getPrefix(String namespaceURI) { + return namespaces2.get(namespaceURI); + } + + @Override + public Iterator<?> getPrefixes(String namespaceURI) { + return null; + } + }; + xpath.setNamespaceContext(ctx); + } else { + namespaces2 = null; + this.namespaces = null; + } + } + + @Override + public void parseFile(File file) throws IOException { + + try { + + // Recherche des clés à partir d'un xpath + Document doc = builder.parse(file.getAbsolutePath()); + XPathExpression expression = xpath.compile(rules); + NodeList list = (NodeList) + expression.evaluate(doc, XPathConstants.NODESET); + getLog().info("Detected nodes [" + file + "] : " + list.getLength()); + for (int index = 0; index < list.getLength(); index++) { + Node node = list.item(index); + + parseLine(file, node.getTextContent()); + } + } catch (Exception e) { + throw new ParserException(e); + } + } + + @Override + public void parseLine(File file, String key) throws IOException { + + key = extract(key); + if (key != null) { + setTouched(true); + registerKey(key); + } + } + } +} Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfigMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfigMojo.java 2010-11-11 10:52:10 UTC (rev 1794) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaActionConfigMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -37,7 +37,9 @@ * @author tchemit <chemit@codelutin.com> * @goal parserJavaActionConfig * @phase generate-resources + * @deprecated since 2.0, will not be replaced (was used by {@code jaxx-swing-action} project which is dead...) */ +@Deprecated public class ParserJavaActionConfigMojo extends ParserJavaMojo { protected static final Pattern MATCH_PATTERN = Pattern.compile("(name|shortDescription|longDescription|name2|shortDescription2|longDescription2)\\s*=\\s*\"([\\w|\\.]+)\"(|\\s*|\\s*,\\s*$)"); Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfigMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfigMojo.java 2010-11-11 10:52:10 UTC (rev 1794) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserJavaTabConfigMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -31,7 +31,9 @@ * @author tchemit <chemit@codelutin.com> * @goal parserJavaTabConfig * @phase generate-resources + * @deprecated since 2.0, will not be replaced (was used by {@code jaxx-swing-action} project which is dead...) */ +@Deprecated public class ParserJavaTabConfigMojo extends ParserJavaActionConfigMojo { @Override Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidationMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidationMojo.java 2010-11-11 10:52:10 UTC (rev 1794) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserValidationMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -41,17 +41,16 @@ import java.net.URLConnection; /** - * Récupération des chaine à traduire depuis les fichiers xml de validation. - * <p/> - * Le goal doit etre execute avant que les resources soient copiees dans - * target/classes pour rendre operatne le file updater (sinon lesfichiers sont - * toujours a jour...) + * Find i18n keys from xworks xml validation files. * + * <b>Note: </b> this goal must always be invoked before the {@code process-resources} + * phase, otherwise all files will be considered as uptodate. + * * @author tchemit <chemit@codelutin.com> * @goal parserValidation * @phase generate-resources */ -public class ParserValidationMojo extends ParserXmlMojo { +public class ParserValidationMojo extends AbstractParserXmlMojo { final URL xworksResource = getClass().getResource("/xwork-validator-1.0.2.dtd"); @@ -70,11 +69,16 @@ protected File cp; /** - * Regles xml. + * Defines the core rules file used to detect i18n keys in xml validation + * files. + * <p/> + * <b>Note :</b> If you do not want to use it, set it to empty and fill the + * {@link #userRulesFiles} parameter. * - * @parameter expression="${i18n.rulesValidation}" default-value="validation.rules" + * @parameter expression="${i18n.coreRuleFile}" default-value="validation.rules" + * @since 2.0 */ - protected String rulesValidation; + protected String coreRuleFile; /** * default src for an entry. @@ -92,6 +96,15 @@ */ protected boolean useLocalResolver; + /** + * Defines the file name of the getter where to put detected i18n keys while getter phase. + * + * @parameter expression="${i18n.outputGetter}" default-value="validation.getter" + * @since 2.0 + */ + protected String outputGetter; + + @Override public String[] getDefaultIncludes() { return new String[]{defaultIncludes}; @@ -122,19 +135,14 @@ @Override protected String getOutGetter() { - return "validation.getter"; + return outputGetter; } @Override - protected String getFileRules() { - return rulesValidation; + protected String getCoreRuleFile() { + return coreRuleFile; } - @Override - protected String getCoreFileRules() { - return "validation.rules"; - } - protected XmlFileParser newXmlFileParser(final XPath xpath, final DocumentBuilder builder) { @@ -147,7 +155,7 @@ showTouchedFiles, rules, xpath, - builder) { + builder, namespaces) { @Override public String extract(String i18nString) { String s = null; Modified: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlMojo.java 2010-11-11 10:52:10 UTC (rev 1794) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -53,7 +53,9 @@ * Récupération des chaines à traduire depuis les fichiers xml. * * @author julien + * @deprecated since 2.0, prefer use the {@link AbstractParserXmlMojo} instead. */ +@Deprecated public abstract class ParserXmlMojo extends AbstractI18nParserMojo { /** Taille du buffer pour les lectures/écritures */ @@ -91,7 +93,6 @@ try { // never forget this! builder = documentBuilderFactory.newDocumentBuilder(); - } catch (ParserConfigurationException ex) { throw new IllegalStateException( "could not load DocumentBuilder for reason " + Added: trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlUserMojo.java =================================================================== --- trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlUserMojo.java (rev 0) +++ trunk/maven-i18n-plugin/src/main/java/org/nuiton/i18n/plugin/parser/impl/ParserXmlUserMojo.java 2010-11-11 10:52:30 UTC (rev 1795) @@ -0,0 +1,168 @@ +/* + * #%L + * I18n :: Maven Plugin + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2007 - 2010 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 + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.i18n.plugin.parser.impl; + +import org.nuiton.i18n.plugin.parser.I18nSourceEntry; +import org.nuiton.i18n.plugin.parser.SourceEntry; +import org.nuiton.io.FileUpdater; +import org.nuiton.io.MirroredFileUpdater; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.xpath.XPath; +import java.io.File; + +/** + * To obtain i18n keys from xml files using the {@code userRulesFiles} (and + * an optional {@code coreRuleFile} if any serves your purpose). + * <p/> + * <b>Note: </b> this goal must always be invoked before the + * {@code process-resources} phase, otherwise all files will be considered as + * uptodate. + * + * @author tchemit <chemit@codelutin.com> + * @goal parserXml + * @phase generate-resources + * @since 2.0 + */ +public class ParserXmlUserMojo extends AbstractParserXmlMojo { + + /** + * Default directory where to look for files. + * + * @parameter expression="${i18n.xmlBasedir}" default-value="${basedir}/src/main/resources" + * @required + * @since 2.0 + */ + protected File basedir; + + /** + * Defines files to parse. + * + * @parameter expression="${i18n.xmlIncludes}" + * @required + * @since 2.0 + */ + protected String includes; + + /** + * Defines an optional files which contain xpath rules to obtain i18n + * keys in xml files and is defined in plugin. + * + * @parameter expression="${i18n.coreRuleFiles}" + * @since 2.0 + */ + protected String coreRuleFile; + + /** + * Defines where included files will be copied. + * <p/> + * Knowing this permits us to parse included xml files only if they were + * modified from a previous build. + * + * @parameter expression="${i18n.cp}" default-value="${basedir}/target/classes" + * @since 2.0 + */ + protected File cp; + + /** + * Defines the file name of the getter where to put detected i18n keys while getter phase. + * + * @parameter expression="${i18n.outputGetter}" default-value="xmlUser.getter" + * @since 2.0 + */ + protected String outputGetter; + + @Override + public String[] getDefaultIncludes() { + return new String[]{includes}; + } + + @Override + public String[] getDefaultExcludes() { + return I18nSourceEntry.EMPTY_STRING_ARRAY; + } + + @Override + public File getDefaultBasedir() { + return basedir; + } + + @Override + protected String getCoreRuleFile() { + return coreRuleFile; + } + + @Override + protected XmlFileParser newXmlFileParser(XPath xpath, DocumentBuilder builder) { + XmlFileParser fileParser = new XmlFileParser(getLog(), + getEncoding(), + oldParser, + showTouchedFiles, + rules, + xpath, + builder, namespaces) { + @Override + public String extract(String i18nString) { + String s = null; + if (!i18nString.trim().isEmpty()) { + s = i18nString.trim(); + } + if (getLog().isDebugEnabled()) { + getLog().debug(i18nString + " = " + s); + } + return s; + } + }; + return fileParser; + } + + @Override + protected String getOutGetter() { + return outputGetter; + } + + @Override + protected String getKeyModifierStart() { + return null; + } + + @Override + protected String getKeyModifierEnd() { + return null; + } + + @Override + public FileUpdater newFileUpdater(SourceEntry entry) { + return new MirroredFileUpdater("", "", entry.getBasedir(), cp) { + + @Override + public File getMirrorFile(File f) { + String file = + f.getAbsolutePath().substring(prefixSourceDirecotory); + return new File(destinationDirectory + File.separator + file); + } + }; + } +} \ No newline at end of file
participants (1)
-
tchemit@users.nuiton.org