Author: tchemit Date: 2009-03-29 13:36:44 +0000 (Sun, 29 Mar 2009) New Revision: 1281 Added: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/AbstractJaxxMojo.java jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxHelpGeneratorMojo.java jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/NodeItem.java jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/TemplateGenerator.java jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm jaxx/trunk/maven-jaxx-plugin/src/test/java/org/codelutin/jaxx/NodeItemTest.java Modified: jaxx/trunk/maven-jaxx-plugin/changelog.txt jaxx/trunk/maven-jaxx-plugin/pom.xml jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxGeneratorMojo.java jaxx/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties Log: add generate-help goal Modified: jaxx/trunk/maven-jaxx-plugin/changelog.txt =================================================================== --- jaxx/trunk/maven-jaxx-plugin/changelog.txt 2009-03-29 13:36:21 UTC (rev 1280) +++ jaxx/trunk/maven-jaxx-plugin/changelog.txt 2009-03-29 13:36:44 UTC (rev 1281) @@ -1,4 +1,5 @@ 1.3 chemit 20090321 + * 20090327 [chemit] - add javax help mecanism * 20090301 [chemit] - add a profile mode (-Djaxx.profile) 1.2 letelier 2009022? Modified: jaxx/trunk/maven-jaxx-plugin/pom.xml =================================================================== --- jaxx/trunk/maven-jaxx-plugin/pom.xml 2009-03-29 13:36:21 UTC (rev 1280) +++ jaxx/trunk/maven-jaxx-plugin/pom.xml 2009-03-29 13:36:44 UTC (rev 1281) @@ -1,3 +1,4 @@ + <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> @@ -87,6 +88,16 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>1.5</version> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.1</version> + </dependency> </dependencies> Added: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/AbstractJaxxMojo.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/AbstractJaxxMojo.java (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/AbstractJaxxMojo.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,170 @@ +/* *##% + * Copyright (C) 2007 + * JaxxPlugin, Code Lutin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ +package org.codelutin.jaxx; + +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 java.io.File; + +/** + * Abract Jaxx Mojo. + * + * @author chemit + * + * @since 1.3 + */ +public abstract class AbstractJaxxMojo extends AbstractMojo { + + /** + * Dépendance du projet. + * + * @parameter default-value="${project}" + * @required + * @readonly + */ + protected MavenProject project; + /** + * Repertoire de destination des fichiers java a generer. + * + * @parameter expression="${jaxx.outJava}" default-value="${basedir}/target/generated-sources/java" + */ + protected File outJava; + /** + * verbose flag + * + * @parameter expression="${jaxx.verbose}" default-value="false" + * + * @since 1.3 + */ + protected boolean verbose; + /** + * to make compiler i18nable, says add the {@link org.codelutin.i18n.I18n#_(String, Object[])} method + * invocation on {@link jaxx.compiler.I18nHelper#I18N_ATTRIBUTES} attributes. + * + * @parameter expression="${jaxx.i18nable}" default-value="true" + * @see jaxx.compiler.I18nHelper + */ + protected boolean i18nable; + /** + * The store of helpIds generated by {@link JaxxGeneratorMojo}. + * <p/> + * + * @parameter expression="${jaxx.helpIdStore}" default-value="target/helpIds.properties" + * @required + * + * @since 1.3 + */ + protected File helpIdStore; + /** + * The name of the helpset to generate. + * + * @parameter expression="${jaxx.helpSetName}" default-value="${project.artifactId}" + * @required + * + * @since 1.3 + */ + protected String helpSetName; + /** + * The prefix to add to i18n key for any help i18n key. + * + * @parameter expression="${jaxx.helpsetI18nPrefix}" default-value="${jaxx.helpSetName}.help." + * @required + * + * @since 1.3 + */ + protected String helpsetI18nPrefix; + /** + * The suffix to add to i18n key for an help Id. + * + * @parameter expression="${jaxx.helpsetTitleI18nSuffix}" default-value=".title" + * @required + * + * @since 1.3 + */ + protected String helpsetTitleI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @parameter expression="${jaxx.helpsetTocI18nSuffix}" default-value=".toc" + * @required + * + * @since 1.3 + */ + protected String helpsetTocI18nSuffix; + /** + * The suffix to add to i18n key for an toc Id. + * + * @parameter expression="${jaxx.helpsetIndexI18nSuffix}" default-value=".index" + * @required + * + * @since 1.3 + */ + protected String helpsetIndexI18nSuffix; + protected boolean skip = true; + protected ClassLoader cl; + + public abstract void init() throws Exception; + + public abstract void doAction() throws Exception; + + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + + try { + init(); + } catch (Exception e) { + if (e instanceof MojoFailureException) { + throw (MojoFailureException) e; + } + if (e instanceof MojoExecutionException) { + throw (MojoExecutionException) e; + } + throw new MojoExecutionException("error in init : " + e.getMessage(), e); + } + + if (skip) { + if (verbose) { + getLog().info("jaxx - skip!"); + } + return; + } + + try { + + doAction(); + + } catch (Exception e) { + //getLog().error(e); + Throwable e2 = e; + while (e2.getCause() != null) { + e2 = e.getCause(); + } + getLog().error(e2); + + throw new MojoExecutionException(e2.getMessage(), e2); + } finally { + System.gc(); + } + + } + +} \ No newline at end of file Modified: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxGeneratorMojo.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxGeneratorMojo.java 2009-03-29 13:36:21 UTC (rev 1280) +++ jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxGeneratorMojo.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *##%*/ - package org.codelutin.jaxx; import jaxx.beaninfos.BeanInfoUtil; @@ -25,17 +24,14 @@ import jaxx.compiler.JAXXCompilerLaunchor; import jaxx.runtime.JAXXContext; import jaxx.tags.TagManager; -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.plugin.logging.Log; -import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.DirectoryScanner; import org.codelutin.util.FileUpdaterHelper; import org.codelutin.util.MirroredFileUpdater; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.Modifier; import java.net.MalformedURLException; @@ -44,8 +40,12 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Properties; import java.util.Set; import jaxx.compiler.CompiledObjectDecorator; +import jaxx.compiler.HelpRootCompiledObjectDecorator; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.project.MavenProject; /** * Classe permettant de transformer des sources jaxx vers du source java. @@ -56,112 +56,79 @@ * @requiresDependencyResolution compile * @requiresProject */ -public class JaxxGeneratorMojo extends AbstractMojo { +public class JaxxGeneratorMojo extends AbstractJaxxMojo { /** - * Dépendance du projet. - * - * @parameter default-value="${project}" - * @required - * @readonly - */ - protected MavenProject project; - - /** * Le compilateur à utiliser (par défaut celui de Swing) * * @parameter expression="${jaxx.compilerFQN}" default-value="jaxx.compiler.SwingCompiler" */ protected String compilerFQN; - /** * Le compilateur à utiliser (par défaut celui de Swing) * * @parameter expression="${jaxx.validatorFQN}" default-value="jaxx.runtime.validator.swing.SwingValidator" */ protected String validatorFQN; - /** - * Repertoire de destination des fichiers java a generer. - * - * @parameter expression="${jaxx.outJava}" default-value="${basedir}/target/generated-sources/java" - */ - protected File outJava; - /** - * flag to include in compiler classpath the java sources directories (src and outJava). - * <p/> - * By default, false. - * - * @parameter expression="${jaxx.addSourcesToClassPath}" default-value="false" - */ - protected boolean addSourcesToClassPath; - - /** - * flag to include in compiler classpath the project compile classpath. - * <p/> - * By default, false. - * - * @parameter expression="${jaxx.addProjectClassPath}" default-value="false" - */ - protected boolean addProjectClassPath; - - /** * chemin du repertoire de generation des resources. * * @parameter expression="${jaxx.outResource}" default-value="${basedir}/target/generated-sources/resources" */ protected File outResource; - /** * chemin du repertoire de compilation des resources. * * @parameter expression="${jaxx.outClass}" default-value="${basedir}/target/classes" */ protected File outClass; - /** - * verbose flag - * - * @parameter expression="${jaxx.verbose}" default-value="false" - */ - protected boolean verbose; - - /** * Repertoire sources des fichiers jaxx a generer. * * @parameter expression="${jaxx.src}" default-value="${maven.src.dir}/main/java" */ protected File src; - /** * pour optimizer le code compile ou genere ? * * @parameter expression="${jaxx.optimize}" default-value="false" */ protected boolean optimize; - /** * les options de la compilation * * @parameter expression="${jaxx.javaOpts}" */ protected String javaOpts = null; - /** * pour filter les fichiers a traiter * * @parameter expression="${jaxx.includes}" */ protected String[] includes; - /** * pour filter les fichiers a ne pas traiter * * @parameter expression="${jaxx.excludes}" */ protected String[] excludes; - /** + * flag to include in compiler classpath the java sources directories (src and outJava). + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addSourcesToClassPath}" default-value="false" + */ + protected boolean addSourcesToClassPath; + /** + * flag to include in compiler classpath the project compile classpath. + * <p/> + * By default, false. + * + * @parameter expression="${jaxx.addProjectClassPath}" default-value="false" + */ + protected boolean addProjectClassPath; + /** * to force generation of java source for any jaxx files with no timestamp checking. * <p/> * By default, never force generation. @@ -169,18 +136,7 @@ * @parameter expression="${jaxx.force}" default-value="false" */ protected boolean force; - /** - * to make compiler i18nable, says add the {@link org.codelutin.i18n.I18n#_(String, Object[])} method - * invocation on {@link jaxx.compiler.I18nHelper#I18N_ATTRIBUTES} attributes. - * - * @parameter expression="${jaxx.i18nable}" default-value="true" - * @see jaxx.compiler.I18nHelper - */ - protected boolean i18nable; - - - /** * flag to add logger to each generated jaxx file. * <p/> * By default, always add it. @@ -196,7 +152,6 @@ * @parameter expression="${jaxx.resetAfterCompile}" default-value="true" */ protected boolean resetAfterCompile; - /** * the name of implementation of {@link jaxx.runtime.JAXXContext} * to be used on {@link jaxx.runtime.JAXXObject}. @@ -207,7 +162,6 @@ * @required */ protected String jaxxContextImplementorClass; - /** * extra path to be added in {@link java.beans.Introspector#setBeanInfoSearchPath(String[])}. * <p/> @@ -221,15 +175,22 @@ * @parameter expression="${jaxx.beanInfoSearchPath}" */ protected String[] beanInfoSearchPath; - /** * list of fqn of class toimport for all generated jaxx files * * @parameter expression="${jaxx.extraImports}" + * + * @deprecated Prefer use of extraImportList as a string, so + * could be use in properties section. */ protected String[] extraImports; - /** + * list of fqn of class toimport for all generated jaxx files + * + * @parameter expression="${jaxx.extraImportList}" + */ + protected String extraImportList; + /** * the FQN of the ui to use for error notification. * <p/> * If not given, will use the one defined in validator @@ -238,8 +199,7 @@ * @see jaxx.runtime.validator.swing.SwingValidator#DEFAULT_UI_CLASS */ protected String defaultErrorUIFQN; - - /** + /** * the FQN of the ui to use for error notification. * <p/> * If not given, will use the one defined in validator @@ -249,7 +209,6 @@ * @see jaxx.compiler.CompiledObjectDecorator */ protected String defaultDecoratorFQN; - /** * a flag to use UIManager to retreave icons. * @@ -264,25 +223,37 @@ * @parameter expression="${jaxx.profile}" default-value="false" */ protected boolean profile; - + /** + * flag to activate help generation process. + * <p/> + * By default, not active. + * + * @parameter expression="${jaxx.generateHelp}" default-value="false" + * + * @since 1.3 + */ + private boolean generateHelp; + /** + * the FQN of help broker + * <p/> + * By default, none. + * + * @parameter expression="${jaxx.helpBrokerFQN}" + * + * @since 1.3 + */ + private String helpBrokerFQN; protected String[] files; - private static final String[] INCLUDES = {"**\\/*.jaxx"}; - protected CompilerOptions options; - protected MirroredFileUpdater updater; - - protected boolean skip = true; - private Class<?> defaultErrorUIClass; private Class<? extends CompiledObjectDecorator> defaultDecoratorClass; - - protected ClassLoader cl; private Class<? extends JAXXCompiler> compilerClass; @SuppressWarnings("unchecked") - protected void init() throws ClassNotFoundException, MalformedURLException { + @Override + public void init() throws Exception { if (project != null && ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging()))) { // nothing to be done for this type of packaging @@ -291,12 +262,19 @@ return; } + if (generateHelp) { + // check there is some bundle + if (helpIdStore == null) { + throw new MojoFailureException("you must set the helpIdStore property."); + } + } + compilerClass = (Class<? extends JAXXCompiler>) Class.forName(compilerFQN); - defaultDecoratorClass = (Class<? extends CompiledObjectDecorator>) Class.forName(defaultDecoratorFQN); - + defaultDecoratorClass = (Class<? extends CompiledObjectDecorator>) Class.forName(defaultDecoratorFQN); + // check the validator class is correct Class.forName(validatorFQN); - + if (defaultErrorUIFQN != null && !defaultErrorUIFQN.trim().isEmpty()) { defaultErrorUIClass = Class.forName(defaultErrorUIFQN); } @@ -362,7 +340,18 @@ this.files = listFiles.toArray(new String[listFiles.size()]); } + if (extraImportList != null && !extraImportList.isEmpty()) { + String[] imports = extraImportList.split(","); + int i = 0; + for (String importS : imports) { + imports[i++] = importS.trim(); + } + if (verbose) { + getLog().info("extra imports " + java.util.Arrays.toString(imports)); + } + extraImports = imports; + } options = toCompilerOptions(); if (verbose) { @@ -371,6 +360,43 @@ } + @Override + public void doAction() throws MojoExecutionException { + getLog().info("jaxx - detects " + this.files.length + " modify jaxx file(s). "); + + try { + + // force compiler init from here, not in a static block + TagManager.reset(verbose); + + JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.newLaunchor(src, files, options); + boolean success = launchor.compile(); + getLog().info("jaxx - generate " + launchor.getCompilerCount() + " file(s). "); + + if (!success) { + throw new MojoExecutionException("Aborting due to errors reported by jaxxc"); + } + + if (generateHelp) { + // generate help + generateHelp(); + } + + } catch (MojoExecutionException e) { + getLog().error(e); + throw e; + } catch (Exception e) { + //getLog().error(e); + Throwable e2 = e; + while (e2.getCause() != null) { + e2 = e.getCause(); + } + getLog().error(e2); + + throw new MojoExecutionException(e2.getMessage(), e2); + } + } + public CompilerOptions toCompilerOptions() { CompilerOptions result = new CompilerOptions(); result.setClassPath(src.getPath()); @@ -393,86 +419,116 @@ result.setDefaultErrorUI(defaultErrorUIClass); result.setUseUIManagerForIcon(useUIManagerForIcon); result.setDefaultDecoratorClass(defaultDecoratorClass); + result.setGenerateHelp(generateHelp); + result.setHelpBrokerFQN(helpBrokerFQN); + result.setHelpsetTitleI18nSuffix(helpsetTitleI18nSuffix); + result.setHelpsetIndexI18nSuffix(helpsetIndexI18nSuffix); + result.setHelpsetTocI18nSuffix(helpsetTocI18nSuffix); + result.setHelpSetName(helpSetName); + result.setHelpsetI18nPrefix(helpsetI18nPrefix); + if (cl != null) { result.setClassLoader(cl); } return result; } - @Override - public void execute() throws MojoExecutionException, MojoFailureException { + protected void fixCompileSourceRoots() { + //fixme should remove this silly test when we will make real maven plugin tests :) + if (project != null) { + if (!project.getCompileSourceRoots().contains(outJava.getPath())) { + project.addCompileSourceRoot(outJava.getPath()); + } + } + } - try { - init(); - } catch (ClassNotFoundException e) { - throw new MojoExecutionException("error in init : " + e.getMessage(), e); - } catch (MalformedURLException e) { - throw new MojoExecutionException("error in init : " + e.getMessage(), e); + protected void printInit() { + getLog().info(options.toString()); + getLog().info("includes : " + Arrays.toString(includes)); + for (String file : files) { + getLog().info("will generate " + file); } - if (skip) { - if (verbose) { - getLog().info("jaxx - skip!"); + ClassLoader threadLoader = Thread.currentThread().getContextClassLoader(); + getLog().info(threadLoader.toString()); + if (threadLoader.getClass().getSimpleName().equals("RealmClassLoader")) { + try { + java.lang.reflect.Method m = threadLoader.getClass().getDeclaredMethod("getURLs"); + m.setAccessible(true); + URL[] urls = (URL[]) m.invoke(threadLoader); + + for (URL url : urls) { + getLog().info("url in class loader " + url); + } + } catch (Exception e) { + getLog().warn("??? : " + e.getMessage(), e); } - return; } - if (files.length == 0) { - getLog().info("jaxx - no jaxx file to treate. "); - return; + //fixme should remove this silly test when we will make real maven plugin tests :) + if (getPluginContext() != null) { + for (Object e : getPluginContext().keySet()) { + getLog().info("pluginContext " + e + " : " + getPluginContext().get(e)); + } } + } + protected void checkJaxxContextImplementorClass() { + if (jaxxContextImplementorClass == null) { + throw new IllegalArgumentException("jaxxContextImplementor can not be null"); + } try { - doAction(); - } finally { - System.gc(); + Class jaxxContextImplementor = Class.forName(jaxxContextImplementorClass); + if (!JAXXContext.class.isAssignableFrom(jaxxContextImplementor)) { + throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' does not implements " + JAXXContext.class); + } + if (Modifier.isAbstract(jaxxContextImplementor.getModifiers())) { + throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' can not be abstract."); + + } + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException("could not find jaxxContextImplementor class : " + jaxxContextImplementorClass); } - } - public void doAction() throws MojoExecutionException { - getLog().info("jaxx - detects " + this.files.length + " modify jaxx file(s). "); + protected void generateHelp() throws IOException { + Set<String> helpIds = HelpRootCompiledObjectDecorator.getHelpIds(); + if (helpIds.isEmpty()) { + if (verbose) { + // no ids detected in this compilation round + getLog().info("no helpIds detected."); + } + return; + } - try { + if (!helpIdStore.getParentFile().exists()) { + helpIdStore.getParentFile().mkdirs(); + } - // force compiler init from here, not in a static block - TagManager.reset(verbose); + Properties p = new Properties(); - JAXXCompilerLaunchor launchor = JAXXCompilerLaunchor.newLaunchor(src, files, options); - boolean success = launchor.compile(); - getLog().info("jaxx - generate " + launchor.getCompilerCount() + " file(s). "); + for (String helpId : helpIds) { + String path = helpId.replaceAll("\\.", File.separator); + path = removeQuote(path) + ".html"; + p.put(removeQuote(helpId), path); + } - if (!success) { - throw new MojoExecutionException("Aborting due to errors reported by jaxxc"); - } + FileOutputStream w = new FileOutputStream(helpIdStore); - } catch (MojoExecutionException e) { - getLog().error(e); - throw e; - } catch (Exception e) { - //getLog().error(e); - Throwable e2 = e; - while (e2.getCause() != null) { - e2 = e.getCause(); - } - getLog().error(e2); - - throw new MojoExecutionException(e2.getMessage(), e2); + try { + p.store(w, null); + } finally { + w.close(); } - } - protected void fixCompileSourceRoots() { - //fixme should remove this silly test when we will make real maven plugin tests :) - if (project != null) { - if (!project.getCompileSourceRoots().contains(outJava.getPath())) { - project.addCompileSourceRoot(outJava.getPath()); - } - } + getLog().info("helpIdStore generated in " + helpIdStore); + + helpIds.clear(); } @SuppressWarnings({"unchecked"}) - protected URLClassLoader initClassLoader(MavenProject project, Log log) throws MalformedURLException { - URLClassLoader loader; + protected URLClassLoader initClassLoader(MavenProject project, org.apache.maven.plugin.logging.Log log) throws MalformedURLException { + URLClassLoader loader = null; if (project != null) { URLClassLoader result; @@ -499,7 +555,7 @@ result = new URLClassLoader(lUrls.toArray(new URL[lUrls.size()]), getClass().getClassLoader()); } catch (IOException e) { - throw new RuntimeException("Can't create ClassLoader for script, bad directory: " + outClass + " for reason " + e.getMessage(), e); + throw new RuntimeException("Can't create ClassLoader for reason " + e.getMessage(), e); } loader = result; } else { @@ -517,53 +573,13 @@ return loader; } - protected void printInit() { - getLog().info(options.toString()); - getLog().info("includes : " + Arrays.toString(includes)); - for (String file : files) { - getLog().info("will generate " + file); + protected String removeQuote(String txt) { + if (txt.startsWith("\"")) { + txt = txt.substring(1); } - - ClassLoader threadLoader = Thread.currentThread().getContextClassLoader(); - getLog().info(threadLoader.toString()); - if (threadLoader.getClass().getSimpleName().equals("RealmClassLoader")) { - try { - java.lang.reflect.Method m = threadLoader.getClass().getDeclaredMethod("getURLs"); - m.setAccessible(true); - URL[] urls = (URL[]) m.invoke(threadLoader); - - for (URL url : urls) { - getLog().info("url in class loader " + url); - } - } catch (Exception e) { - getLog().warn("??? : " + e.getMessage(), e); - } + if (txt.endsWith("\"")) { + txt = txt.substring(0, txt.length() - 1); } - - //fixme should remove this silly test when we will make real maven plugin tests :) - if (getPluginContext() != null) { - for (Object e : getPluginContext().keySet()) { - getLog().info("pluginContext " + e + " : " + getPluginContext().get(e)); - } - } + return txt; } - - protected void checkJaxxContextImplementorClass() { - if (jaxxContextImplementorClass == null) { - throw new IllegalArgumentException("jaxxContextImplementor can not be null"); - } - try { - Class jaxxContextImplementor = Class.forName(jaxxContextImplementorClass); - if (!JAXXContext.class.isAssignableFrom(jaxxContextImplementor)) { - throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' does not implements " + JAXXContext.class); - } - if (Modifier.isAbstract(jaxxContextImplementor.getModifiers())) { - throw new IllegalArgumentException("jaxxContextImplementor '" + jaxxContextImplementor + "' can not be abstract."); - - } - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("could not find jaxxContextImplementor class : " + jaxxContextImplementorClass); - } - } - } \ No newline at end of file Added: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxHelpGeneratorMojo.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxHelpGeneratorMojo.java (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/JaxxHelpGeneratorMojo.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,792 @@ +/* *##% + * Copyright (C) 2007 + * JaxxPlugin, Code Lutin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ +package org.codelutin.jaxx; + +import org.apache.maven.plugin.MojoFailureException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.Stack; +import org.apache.maven.model.Resource; +import org.codelutin.i18n.I18n; +import org.codelutin.util.FileUtil; +import org.codelutin.util.SortedProperties; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; +import static org.codelutin.i18n.I18n._; + +/** + * Mojo to generate javax help stuff for your project. + * + * HelpIds should have been discovered by the JaxxMojo. + * + * @author chemit + * @goal generate-help + * @phase process-sources + * + * @requiresProject + * @requiresDependencyResolution compile + * @since 1.3 + */ +public class JaxxHelpGeneratorMojo extends AbstractJaxxMojo { + + /** + * The directory where to generate javaHelp skeleton files. + * <p/> + * Is required if generateHelp is on. + * + * @parameter expression="${jaxx.helpTarget}" alias="target" default-value="${maven.src.dir}/main/help" + * @required + * + * @since 1.3 + */ + protected File target; + /** + * The locale to generate for help. + * + * By default, stay in France. + * + * @parameter expression="${jaxx.locale}" default-value="fr" + * @required + * + * @since 1.3 + */ + protected String locale; + /** + * The package where to generate i18n java file. + * + * @parameter expression="${jaxx.packageName}" default-value="${project.groupId}" + * @required + * + * @since 1.3 + */ + protected String packageName; + /** + * The file name of the helpset to generate. + * + * @parameter expression="${jaxx.helpSetFileName}" default-value="${jaxx.helpSetName}.hs" + * @required + * + * @since 1.3 + */ + protected String helpsetFileName; + /** + * The file name of the helpset map to generate. + * + * @parameter expression="${jaxx.mapFileName}" default-value="${jaxx.helpSetName}Map.jhm" + * @required + * + * @since 1.3 + */ + protected String mapFileName; + /** + * The file name of the helpset index to generate. + * + * @parameter expression="${jaxx.indexFileName}" default-value="${jaxx.helpSetName}Index.xml" + * @required + * + * @since 1.3 + */ + protected String indexFileName; + /** + * The file name of the helpset toc to generate. + * + * @parameter expression="${jaxx.tocFileName}" default-value="${jaxx.helpSetName}TOC.xml" + * @required + * + * @since 1.3 + */ + protected String tocFileName; + /** + * The file name of the i18n java file to generate. + * + * @parameter expression="${jaxx.i8nFileName}" default-value="${jaxx.helpSetName}I18n.java" + * @required + * + * @since 1.3 + */ + protected String i8nFileName; + /** + * The template used to generate helpset file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.helpSetTemplate}" default-value="/defaultHelpSet.hs.vm" + * @required + * + * @since 1.3 + */ + protected File helpSetTemplate; + /** + * The template used to generate helpset map file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.mapTemplate}" default-value="/defaultMap.jhm.vm" + * @required + * + * @since 1.3 + */ + protected File mapTemplate; + /** + * The template used to generate helpset index file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.indexTemplate}" default-value="/defaultIndex.xml.vm" + * @required + * + * @since 1.3 + */ + protected File indexTemplate; + /** + * The template used to generate helpset toc file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.tocTemplate}" default-value="/defaultToc.xml.vm" + * @required + * + * @since 1.3 + */ + protected File tocTemplate; + /** + * The template used to generate helpset content file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.contentTemplate}" default-value="/defaultContent.html.vm" + * @required + * + * @since 1.3 + */ + protected File contentTemplate; + /** + * The template used to generate helpset content file. + * + * Must be an existing file or a ressource in classp-ath + * + * @parameter expression="${jaxx.i18nTemplate}" default-value="/defaultI18n.java.vm" + * @required + * + * @since 1.3 + */ + protected File i18nTemplate; + /** + * The help ids discovered by Jaxx compilation + */ + protected Properties helpIds; + private static final String AUTOREMOVE_LINE = "REMOVE THS LINE TO DISABLE AUTO-REGENERATE THE FILE"; + + @Override + public void init() throws Exception { + + if (project != null && ("pom".equals(project.getPackaging()) || "site".equals(project.getPackaging()))) { + // nothing to be done for this type of packaging + skip = true; + getLog().info("skip generate goal for packaging " + project.getPackaging()); + return; + } + + if (!helpIdStore.exists()) { + skip = true; + getLog().info("no helpIdStore to react at " + helpIdStore); + return; + } + + // check there is some bundle + if (locale == null) { + throw new MojoFailureException("you must set the bundles property."); + } + // check there is some bundle + if (target == null) { + throw new MojoFailureException("you must set the target property."); + } + // check ressources + checkResource(helpSetTemplate); + checkResource(mapTemplate); + checkResource(indexTemplate); + checkResource(tocTemplate); + checkResource(contentTemplate); + + if (!target.exists()) { + getLog().info("mkdir " + target); + target.mkdirs(); + } + + + helpIds = new SortedProperties(); + + InputStream stream = new FileInputStream(helpIdStore); + + helpIds.load(stream); + + stream.close(); + + if (helpIds.isEmpty()) { + + // no ids detected + getLog().warn("no helpIds detected, will skip."); + skip = true; + return; + } + + skip = false; + } + + @Override + public void doAction() throws Exception { + + if (i18nable) { + + List<URL> lUrls = new java.util.ArrayList<URL>(); + List resources = project.getResources(); + for (Object o : resources) { + Resource resource = (Resource) o; + lUrls.add(new File(resource.getDirectory()).toURI().toURL()); + } + I18n.setExtraURL(lUrls.toArray(new URL[lUrls.size()])); + I18n.init(locale, null); + } + + File file; + + Properties env = new Properties(); + + env.put("helpSetName", helpSetName); + env.put("helpSetFileName", helpsetFileName); + env.put("mapFileName", mapFileName); + env.put("indexFileName", indexFileName); + env.put("tocFileName", tocFileName); + env.put("separator", " "); + env.put("autoremoveLine", AUTOREMOVE_LINE); + + + int touchedFiles = 0; + + // --------------------------------------------------------------- + // --- main helpset file ----------------------------------------- + // --------------------------------------------------------------- + + + file = new File(target, helpsetFileName); + + boolean doCreate = generateHelSetFile(file, env); + + if (doCreate) { + touchedFiles++; + } + + // --------------------------------------------------------------- + // --- helpset map file ------------------------------------------ + // --------------------------------------------------------------- + + file = new File(target, mapFileName); + + Properties mergedHelpIds = generateMapFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset index file ---------------------------------------- + // --------------------------------------------------------------- + + file = new File(target, indexFileName); + + NodeItem indexRootItem = generateIndexFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset toc file ------------------------------------------ + // --------------------------------------------------------------- + + file = new File(target, tocFileName); + + NodeItem tocRootItem = generateTocFile(file, env); + touchedFiles++; + + // --------------------------------------------------------------- + // --- helpset content files ------------------------------------- + // --------------------------------------------------------------- + + TemplateGenerator gen = prepareGenerator(contentTemplate); + + Enumeration keys = helpIds.keys(); + + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + String url = (String) helpIds.get(key); + url = helpSetName + File.separator + url; + + File f = new File(target, url); + + boolean exist = f.exists(); + + if (exist) { + // check if there is a autoremoveLine in content + String content = FileUtil.readAsString(f); + if (!content.contains(AUTOREMOVE_LINE)) { + // no regenerate marker detected, so skip this file + if (verbose) { + getLog().debug("skip existing file " + f); + } + continue; + } + } + + f.getParentFile().mkdirs(); + + if (verbose) { + if (exist) { + getLog().info("regenerate content file " + f); + } else { + getLog().info("generate content file " + f); + } + } + + env.put("helpId", key); + String i18n = helpsetI18nPrefix + key + helpsetTitleI18nSuffix; + env.put("helpIdTitle", _(i18n)); + env.put("helpIdUrl", url); + + gen.generate(env, f); + touchedFiles++; + } + + // --------------------------------------------------------------- + // --- i18n file ------------------------------------------------- + // --------------------------------------------------------------- + + String path = packageName.replaceAll("\\.", File.separator); + path += File.separator + i8nFileName; + file = new File(outJava, path); + generateI18nFile(file, env, mergedHelpIds, indexRootItem, tocRootItem); + touchedFiles++; + + getLog().info(touchedFiles + " file(s) treated."); + } + + protected void generateI18nFile(File file, Properties env, Properties mergedHelpIds, NodeItem indexRootItem, NodeItem tocRootItem) throws Exception { + + boolean create = !file.exists(); + + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + + Set<String> keys = new java.util.HashSet<String>(); + + for (Object k : mergedHelpIds.keySet()) { + String key = helpsetI18nPrefix + k + helpsetTitleI18nSuffix; + keys.add(key); + } + indexRootItem.extractI18n(keys, helpsetI18nPrefix, helpsetIndexI18nSuffix); + tocRootItem.extractI18n(keys, helpsetI18nPrefix, helpsetTocI18nSuffix); + + env.put("keys", keys); + env.put("packageName", packageName); + String className = file.getName(); + int index = className.lastIndexOf("."); + className = className.substring(0, index); + env.put("className", className); + + if (verbose) { + if (create) { + getLog().info("generate i18n java file " + file); + } else { + getLog().info("udpate i18n java file " + file); + } + } + + doGen(i18nTemplate, file, env); + + } + + protected boolean generateHelSetFile(File file, Properties env) throws Exception { + + if (file.exists()) { + // check the auto removeline presence + String content = FileUtil.readAsString(file); + if (!content.contains(AUTOREMOVE_LINE)) { + // no regenerate marker detected, so skip this file + if (verbose) { + getLog().info("skip existing helpset main file " + file); + } + return false; + } + } + + if (verbose) { + if (file.exists()) { + getLog().info("regenerate helpset main file " + file); + } else { + getLog().info("generate helpset main file " + file); + } + } + doGen(helpSetTemplate, file, env); + return true; + } + + protected Properties generateMapFile(File file, Properties env) throws Exception { + + boolean create; + + Properties mergedHelpIds = null; + if (file.exists()) { + + // get back the exisiting data and merge it with incoming ones + + if (verbose) { + getLog().info("loading existing helpset map file " + file); + } + + mergedHelpIds = getExistingHelpIds(file); + create = false; + + } else { + + mergedHelpIds = new SortedProperties(); + create = true; + } + + // inject new helpIds + + for (Object k : helpIds.keySet()) { + mergedHelpIds.put(k, helpSetName + "/" + helpIds.get(k)); + } + + if (!mergedHelpIds.contains("top")) { + // on ajoute une entree vers le root du helpset + + String topUrl = helpSetName + ".html"; + helpIds.put("top", topUrl); + mergedHelpIds.put("top", helpSetName + "/" + topUrl); + if (verbose) { + getLog().debug("add top entry with url " + topUrl); + } + } + + if (verbose) { + if (create) { + getLog().info("generate helpset map file " + file); + } else { + getLog().info("udpate helpset map file " + file); + } + } + + env.put("helpIds", mergedHelpIds); + doGen(mapTemplate, file, env); + env.remove("helpIds"); + return mergedHelpIds; + } + + protected NodeItem generateIndexFile(File file, Properties env) throws Exception { + NodeItem rootItem = null; + + boolean create; + + if (file.exists()) { + + create = false; + + rootItem = getExistingItems("indexitem", file); + } else { + create = true; + } + + if (rootItem == null) { + rootItem = new NodeItem("top", helpSetName); + } + + // inject new index entries + + for (Object k : helpIds.keySet()) { + NodeItem toc = rootItem.findChild(k + ""); + if (verbose) { + getLog().debug("index " + k + " : " + toc); + } + } + + //String prefix = helpsetI18nPrefix; + //String prefix = helpsetI18nPrefix + helpSetName + "."; + rootItem.applyI18n(helpsetI18nPrefix, helpsetIndexI18nSuffix); + + if (verbose) { + if (create) { + getLog().info("generate helpset index file " + file); + } else { + getLog().info("udpate helpset index file " + file); + } + } + + env.put("rootItem", rootItem); + doGen(indexTemplate, file, env); + env.remove("rootItem"); + return rootItem; + } + + protected NodeItem generateTocFile(File file, Properties env) throws Exception { + NodeItem rootItem = null; + + boolean create; + + if (file.exists()) { + + create = false; + + rootItem = getExistingItems("tocitem", file); + } else { + create = true; + } + + if (rootItem == null) { + rootItem = new NodeItem("top", helpSetName); + } + // inject new toc entries + + for (Object k : helpIds.keySet()) { + NodeItem toc = rootItem.findChild(k + ""); + if (verbose) { + getLog().debug("toc " + k + " : " + toc); + } + } + + //String prefix = helpsetI18nPrefix + helpSetName + "."; + rootItem.applyI18n(helpsetI18nPrefix, helpsetTocI18nSuffix); + + if (verbose) { + if (create) { + getLog().info("generate helpset toc file " + file); + } else { + getLog().info("udpate helpset toc file " + file); + } + } + + env.put("rootItem", rootItem); + doGen(tocTemplate, file, env); + env.remove("rootItem"); + return rootItem; + } + + protected void doGen(File template, File f, Properties env) throws Exception { + TemplateGenerator gen = prepareGenerator(template); + gen.generate(env, f); + } + + protected TemplateGenerator prepareGenerator(File template) throws Exception { + URL templateURL = getTemplate(template); + + if (verbose) { + getLog().info("using template " + templateURL); + } + TemplateGenerator gen = new TemplateGenerator(project, templateURL); + return gen; + } + + protected URL getTemplate(File f) throws IOException { + URL r = null; + InputStream s = null; + if (f.exists()) { + r = f.toURI().toURL(); + } else { + r = getClass().getResource(f.toString()); + } + return r; + } + + protected void checkResource(File f) throws MojoFailureException { + if (!f.exists()) { + // test in classPath + InputStream r = getClass().getResourceAsStream(f.toString()); + if (r == null) { + throw new MojoFailureException("could not find ressource " + f); + } + } + } + + protected Properties getExistingHelpIds(File file) throws SAXException, IOException { + + final Properties result = new SortedProperties(); + + XMLReader parser = XMLReaderFactory.createXMLReader(); + + parser.setContentHandler(new ContentHandlerAdapter() { + + String target; + String url; + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + if ("mapID".equals(localName)) { + target = atts.getValue("target"); + url = atts.getValue("url"); + if (verbose) { + getLog().debug("detect map entry : " + target + " : " + url); + } + result.put(target, url); + } + } + }); + + InputStream s = new FileInputStream(file); + try { + parser.parse(new InputSource(s)); + } finally { + s.close(); + } + return result; + } + + protected NodeItem getExistingItems(String tagName, File file) throws SAXException, IOException { + + XMLReader parser = XMLReaderFactory.createXMLReader(); + NodeItemHandler handler = new NodeItemHandler(tagName); + + parser.setContentHandler(handler); + + NodeItem rootItem = null; + InputStream s = new FileInputStream(file); + try { + parser.parse(new InputSource(s)); + rootItem = handler.rootItem; + } finally { + s.close(); + } + return rootItem; + } + + static class NodeItemHandler extends ContentHandlerAdapter { + + NodeItem rootItem; + NodeItem currentItem; + final Stack<NodeItem> stack; + final String tagName; + + public NodeItemHandler(String tagName) { + this.tagName = tagName; + this.stack = new Stack<NodeItem>(); + } + + @Override + public void startDocument() throws SAXException { + rootItem = new NodeItem("top", null); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + if (tagName.equals(localName)) { + + String target = atts.getValue("target"); + String text = atts.getValue("text"); + + // debut d'un item + if (currentItem == null) { + // premier item + if (rootItem.getTarget().equals(target)) { + // le premier item est bien top + //rootItem.setText(text); + currentItem = rootItem; + } else { + // le premier noeud n'est pas top + // en l'encapsule + stack.push(rootItem); + currentItem = new NodeItem(target, text); + rootItem.addChild(currentItem); + } + } else { + NodeItem newItem = new NodeItem(target, text); + currentItem.addChild(newItem); + currentItem = newItem; + } + currentItem.adjustTarget(); + stack.push(currentItem); + + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (tagName.equals(localName)) { + // fin d'un item + stack.pop(); + if (!stack.isEmpty()) { + currentItem = stack.peek(); + } + } + } + } + + static class ContentHandlerAdapter implements ContentHandler { + + @Override + public void setDocumentLocator(Locator locator) { + } + + @Override + public void startDocument() throws SAXException { + } + + @Override + public void endDocument() throws SAXException { + } + + @Override + public void startPrefixMapping(String prefix, String uri) throws SAXException { + } + + @Override + public void endPrefixMapping(String prefix) throws SAXException { + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + } + + @Override + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + } + + @Override + public void processingInstruction(String target, String data) throws SAXException { + } + + @Override + public void skippedEntity(String name) throws SAXException { + } + } +} \ No newline at end of file Added: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/NodeItem.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/NodeItem.java (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/NodeItem.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,137 @@ +package org.codelutin.jaxx; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import static org.codelutin.i18n.I18n._; + +public class NodeItem { + + String absoluteTarget; + private String target; + private String text; + private List<NodeItem> childs; + + public NodeItem(String target, String text) { + this.target = target; + this.absoluteTarget = target; + + this.text = text; + } + + public String getTarget() { + return target; + } + + public String getAbsoluteTarget() { + return absoluteTarget; + } + + public String getText() { + return text; + } + + public List<NodeItem> getChilds() { + return childs; + } + + public NodeItem findChild(String path) { + NodeItem result = null; + String[] paths = path.split("\\."); + for (int i = 0, j = paths.length; i < j; i++) { + String p = paths[i]; + if (result == null) { + + // first node + if (target.equals(p)) { + result = this; + continue; + } + result = getChild(p); + if (result == null) { + result = new NodeItem(p, null); + addChild(result); + adjutsAbsoluteTarget(result); + } + continue; + } + NodeItem child = result.getChild(p); + if (child == null) { + child = new NodeItem(p, null); + result.addChild(child); + result.adjutsAbsoluteTarget(child); + result = child; + } else { + result = child; + } + } + return result; + } + + public NodeItem getChild(int index) { + return childs.get(index); + } + + public NodeItem getChild(String target) { + if (isLeaf()) { + return null; + } + for (NodeItem i : childs) { + if (i.target.equals(target)) { + return i; + } + } + return null; + } + + public void addChild(NodeItem child) { + if (childs == null) { + childs = new ArrayList<NodeItem>(); + } + + childs.add(child); + } + + public void adjutsAbsoluteTarget(NodeItem child) { + if (!"top".equals(target)) { + // on ne prefixe pas les fils direct du root + child.absoluteTarget = absoluteTarget + "." + child.target; + } + } + + public void adjustTarget() { + int index = target.lastIndexOf("."); + if (index > -1) { + target = target.substring(index + 1); + } + } + + public boolean isLeaf() { + return childs == null || childs.isEmpty(); + } + + public void applyI18n(String prefix, String suffix) { + String key = prefix + getAbsoluteTarget() + suffix; + text = _(key); + if (!isLeaf()) { + for (NodeItem i : getChilds()) { + i.applyI18n(prefix, suffix); + } + } + } + + public void extractI18n(Set<String> keys, String prefix, String suffix) { + String key = prefix + getAbsoluteTarget() + suffix; + keys.add(key); + if (!isLeaf()) { + for (NodeItem i : getChilds()) { + i.extractI18n(keys, prefix, suffix); + } + } + } + + @Override + public String toString() { + return super.toString() + "<target:" + target + ", text:" + text + ", nbChilds:" + (isLeaf() ? 0 : childs.size()) + ">"; + } +} Added: jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/TemplateGenerator.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/TemplateGenerator.java (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/java/org/codelutin/jaxx/TemplateGenerator.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,142 @@ +/* + * Copyright 2001-2005 The Apache Software Foundation. + * + * 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.codelutin.jaxx; + +import java.io.File; +import java.io.FileWriter; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.maven.project.MavenProject; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +/** + * Generator of template base on velocity. + * + * @author chemit + * @since 1.3 + * + */ +public class TemplateGenerator { + + protected VelocityEngine engine; + protected final MavenProject mavenProject; + protected Template velocityTemplate; + + protected TemplateGenerator(MavenProject mavenProject, URL template) throws URISyntaxException { + + if (mavenProject == null) { + throw new IllegalArgumentException("mavenProject must not be null"); + } + + if (template == null) { + throw new IllegalArgumentException("template must not be null"); + } + + this.mavenProject = mavenProject; + + Properties props = new Properties(); + + String templateName; + + if (template.toURI().isOpaque()) { + + // template is in a jar + + props = new Properties(); + props.setProperty("resource.loader", "jar"); + props.setProperty("jar.resource.loader.description", "Jar resource loader for default webstart templates"); + props.setProperty("jar.resource.loader.class", "org.apache.velocity.runtime.resource.loader.JarResourceLoader"); + + // obtain the jar url + + String url = template.toString(); + int i = url.indexOf("!"); + templateName = url.substring(i + 2); + + props.setProperty("jar.resource.loader.path", url.substring(0, i + 2)); + + } else { + + + templateName = new File(template.getFile()).getName(); + + //props.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, "org.apache.velocity.runtime.log.NullLogSystem"); + props.setProperty("file.resource.loader.path", template.getFile()); + + } + + try { + engine = new VelocityEngine(); + //engine.setProperty("runtime.log.logsystem", new NullLogSystem()); + engine.init(props); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException("Could not initialise Velocity"); + iae.initCause(e); + throw iae; + } + + try { + this.velocityTemplate = engine.getTemplate(templateName); + } catch (Exception e) { + IllegalArgumentException iae = + new IllegalArgumentException("Could not load the template file from '" + template + "'"); + iae.initCause(e); + throw iae; + } + } + + public void generate(Properties context, File outputFile) throws Exception { + + + VelocityContext vcontext = new VelocityContext(); + + // Note: properties that contain dots will not be properly parsed by Velocity. Should we replace dots with underscores ? + addPropertiesToContext(System.getProperties(), vcontext); + + addPropertiesToContext(mavenProject.getProperties(), vcontext); + addPropertiesToContext(context, vcontext); + + vcontext.put("project", mavenProject.getModel()); + + vcontext.put("outputFile", outputFile.getName()); + + FileWriter writer = new FileWriter(outputFile); + + try { + velocityTemplate.merge(vcontext, writer); + writer.flush(); + } catch (Exception e) { + throw new Exception("Could not generate the template " + velocityTemplate.getName() + ": " + e.getMessage(), e); + } finally { + writer.close(); + } + } + + protected void addPropertiesToContext(Properties properties, VelocityContext context) { + + for (Iterator iter = properties.keySet().iterator(); iter.hasNext();) { + String key = (String) iter.next(); + Object value = properties.get(key); + context.put(key, value); + } + + } +} Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultContent.html.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,14 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> +<TITLE> +$helpIdTitle +</TITLE> +</HEAD> +<BODY BGCOLOR="#ffffff"> +<H1>$helpIdTitle</H1> + +<!-- $autoremoveLine --> + +</BODY> +</HTML> Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultHelpSet.hs.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,44 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE helpset + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 1.0//EN" + "http://java.sun.com/products/javahelp/helpset_1_0.dtd"> + +<helpset version="1.0"> + + <!-- $autoremoveLine --> + + <!-- title --> + <title>${helpSetTitle}</title> + + <!-- maps --> + <maps> + <homeID>top</homeID> + <mapref location="$mapFileName"/> + </maps> + + <!-- views --> + <view> + <name>TOC</name> + <label>Table Of Contents</label> + <type>javax.help.TOCView</type> + <data>$tocFileName</data> + </view> + + <view> + <name>Index</name> + <label>Index</label> + <type>javax.help.IndexView</type> + <data>$indexFileName</data> + </view> + +#if ( $!searchData != "" ) + <view> + <name>Search</name> + <label>Search</label> + <type>javax.help.SearchView</type> + <data engine="com.sun.java.help.search.DefaultSearchEngine"> + $searchData + </data> + </view> +#end +</helpset> Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultI18n.java.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,16 @@ +package $packageName; + +$!commentaire +public class $className { // $className + +{ +// BEGIN DO NOT REMOVE : used to detect helper i18n keys +// +#foreach( $key in $keys ) +// _("$key"); +#end +// +// END DO NOT REMOVE : used to detect helper i18n keys +} + +} // $className \ No newline at end of file Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultIndex.xml.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,21 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE index + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Index Version 1.0//EN" + "http://buix.labs.libre-entreprise.org/javahelp/index_1_0.dtd"> + +## pour afficher un org.codelutin.jaxx.NodeItem +#macro ( renderItem $item $prefix ) +#if ( $item.isLeaf() ) +$prefix<indexitem target="$item.absoluteTarget" text="$!item.text"/> +#else +$prefix<indexitem target="$item.absoluteTarget" text="$!item.text"> +#foreach( $child in $item.getChilds() ) +#renderItem( $child "$prefix$separator" ) +#end +$prefix</indexitem> +#end +#end + +<index version="1.0"> +#renderItem( $rootItem $separator ) +</index> Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultMap.jhm.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,16 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE map + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN" + "http://java.sun.com/products/javahelp/map_1_0.dtd"> +<map version="1.0"> + +#if ( !$helpIds.get("toplevelfolder")) + <!-- use this entry to go up in navigation --> + <!--mapID target="toplevelfolder" url="images/toplevel.gif" /--> +#end + +#foreach( $key in $helpIds.keys() ) + <mapID target="$key" url="$helpIds.get($key)" /> +#end + +</map> Added: jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/defaultToc.xml.vm 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8' ?> +<!DOCTYPE toc + PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 1.0//EN" + "http://buix.labs.libre-entreprise.org/javahelp/toc_1_0.dtd"> + +## pour afficher un org.codelutin.jaxx.NodeItem +#macro ( renderItem $item $prefix ) +#if ( $item.isLeaf() ) +$prefix<tocitem target="$item.absoluteTarget" text="$!item.text"/> +#else +$prefix<tocitem target="$item.absoluteTarget" text="$!item.text"> +#foreach( $child in $item.getChilds() ) +#renderItem( $child "$prefix$separator" ) +#end +$prefix</tocitem> +#end +#end +<toc version="1.0"> +#renderItem( $rootItem $separator ) +</toc> Modified: jaxx/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties 2009-03-29 13:36:21 UTC (rev 1280) +++ jaxx/trunk/maven-jaxx-plugin/src/main/resources/log4j.properties 2009-03-29 13:36:44 UTC (rev 1281) @@ -5,5 +5,5 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) %M - %m%n -#log4j.logger.org.codelutin.jaxx=DEBUG +log4j.logger.org.codelutin.i18n=ERROR #log4j.logger.jaxx=DEBUG Added: jaxx/trunk/maven-jaxx-plugin/src/test/java/org/codelutin/jaxx/NodeItemTest.java =================================================================== --- jaxx/trunk/maven-jaxx-plugin/src/test/java/org/codelutin/jaxx/NodeItemTest.java (rev 0) +++ jaxx/trunk/maven-jaxx-plugin/src/test/java/org/codelutin/jaxx/NodeItemTest.java 2009-03-29 13:36:44 UTC (rev 1281) @@ -0,0 +1,54 @@ +package org.codelutin.jaxx; + +import org.junit.Assert; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author tony + */ +public class NodeItemTest { + + @Test + public void testFindChild() { + System.out.println("findChild"); + String path = "a"; + NodeItem instance = new NodeItem("a", "rootItem text"); + NodeItem expResult = new NodeItem("a", "rootItem text"); + NodeItem result = instance.findChild(path); + assertTocItemEquals(expResult, result); + + path = "a.b"; + expResult = new NodeItem("b", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(instance.getChild("b") == result); + assertTrue(instance.findChild("b") == result); + + NodeItem b = result; + + path = "ab"; + expResult = new NodeItem("ab", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(instance.getChild("ab") == result); + assertTrue(instance.findChild("ab") == result); + + path = "a.b.cd"; + expResult = new NodeItem("cd", null); + result = instance.findChild(path); + assertTocItemEquals(expResult, result); + assertTrue(b.getChild("cd") == result); + assertTrue(b.findChild("b.cd") == result); + assertTrue(b.findChild("cd") == result); + assertTrue(instance.findChild("b.cd") == result); + assertTrue(instance.findChild("a.b.cd") == result); + } + + protected void assertTocItemEquals(NodeItem t, NodeItem t2) { + Assert.assertEquals(t.getTarget(), t2.getTarget()); + Assert.assertEquals(t.getText(), t2.getText()); + + } +} \ No newline at end of file