/* * JDynamiTe - Dynamic Template in Java * Copyright (C) 2001, 2002, 2014, Christophe Bouleau * * This file is part of JDynamiTe. * * JDynamiTe 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. * * JDynamiTe 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JDynamiTe. If not, see . * */ package cb.jdynamite.tool; import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import cb.jdynamite.JDynamiTe; import cb.jdynamite.analyser.DefaultAnalyser; import cb.jdynamite.analyser.IDynamicElement; /** * JDynTool is a tool which is based on JDynamiTe, allowing to use JDynamiTe template files by two very simple ways:
* - by command line invocation: no java code is needed,
* - or by JDynTool "run" method call: only few lines of code in your java application.
*

* 1) Command line invocation
*
See {@link JDynTool#main(String[])} usage. *

* 2) Programmatic invocation
*
* Typical instructions sequence in your Java code: *

    *
  1. Create a JDynTool object.

  2. *
  3. For the first call: you have to specify the "JDynamiTe input Template file" in addition to other parameters.
  4. * So, call either {@link JDynTool#run(String, String, Hashtable, boolean)} method,
    * or {@link JDynTool#run(InputStream, String, Hashtable, boolean)} method.

    *
  5. For the subsequent calls (if any):
  6. * You can call the second {@link JDynTool#run(String, Hashtable, boolean)} method, * which will reuse the same template (previously loaded).

    *
  7. Then call {@link JDynamiTe#toString()} method on the JDynamiTe returned object to get the parsing result * (i.e. the populated output document). *
*
* Dependencies:
* In addition to JDynamiTe classes, JDynTool requires "java-getopt-1.0.14.jar", included in JDynamiTe distribution.
* "java-getopt" is a Java port of GNU getopt, provided by Aaron M. Renn * (thanks to him and to developers who support this package). * */ public class JDynTool { private String inputTemplateFileOpt = ""; private InputStream inputStreamTemplateFileOpt; private String defaultRootXMLdoc; private Hashtable keyValuesOpt = new Hashtable(); private boolean verboseOpt = false; private boolean getDefOpt = false; private boolean getKeysOpt = false; private JDynamiTe jDyn; private ArrayList undefinedInputXMLElements; /** * Special variable tag, {__INPUT_TEMPLATE__}, that you can use in your * template, and which is automatically populated with the JDynamiTe input file path string. */ public static final String INPUT_TEMPLATE_PATH_VAR_TAG = "__INPUT_TEMPLATE__"; /** * Creates a JDynTool object and its associated JDynamiTe object. * This JDynTool object is then used to call its {@link #run(String, String, Hashtable, boolean)} method. * @see #run(String, String, Hashtable, boolean) */ public JDynTool() { jDyn = new JDynamiTe("RootJDyn"); undefinedInputXMLElements = new ArrayList(); } /** * Reads, analyses and processes the input template file and then produces * the output result. This method uses a JDynamiTe object to process the * input template file and then produce the output result.
* The global process of this method consists in:
* 1) processing all "simple" JDynamiTe Variables, by calling * {@link JDynamiTe#setVariable(String, String)} method for each key-value * pair.
* 2) processing recursively all XML Dynamic blocks, by calling the * {@link JDynamiTe#parseXMLDynElem()} method. * * @param inputTemplateFile * Input template file path. This path will be used to call the * {@link JDynamiTe#setInput(String)} method. * @param defaultRootXMLInputDoc * Default URI for first level XML dynamic block(s) which do not * have an URI in their definition in template file. This * optional parameter can be null. * @param keyValuesList * List of key-value pairs used to set values to the JDynamiTe * variables contained in the input template. Each key-value pair * will be passed to the * {@link JDynamiTe#setVariable(String, String)} method. * @param verbose * If true, print on stderr output some information messages * during document processing. * @return If the inputTemplateFile can be read and analysed, this method * returns the JDynamiTe object used to process the template * document.
* Use then the {@link JDynamiTe#toString()} method on this returned * object to get the parsing result (i.e. the populated output * document).
* If the inputTemplateFile is undefined or can not be read, this * method returns null. * @see JDynamiTe#setInput(String) * @see JDynamiTe#setVariable(String, String) */ public JDynamiTe run(String inputTemplateFile, String defaultRootXMLInputDoc, Hashtable keyValuesList, boolean verbose) { inputTemplateFileOpt = inputTemplateFile; inputStreamTemplateFileOpt = null; defaultRootXMLdoc = defaultRootXMLInputDoc; if (keyValuesList != null) keyValuesOpt.putAll(keyValuesList); verboseOpt = verbose; return run(true); } /** * Reads, analyses and processes the input template file and then produces * the output result. This method uses a JDynamiTe object to process the * input template file and then produce the output result.
* The global process of this method consists in:
* 1) processing all "simple" JDynamiTe Variables, by calling * {@link JDynamiTe#setVariable(String, String)} method for each key-value * pair.
* 2) processing recursively all XML Dynamic blocks, by calling the * {@link JDynamiTe#parseXMLDynElem()} method. * * @param inputStreamTemplateFile * InputStream attached to the input template. This value will be used to call the * {@link JDynamiTe#setInput(InputStream)} method. * @param defaultRootXMLInputDoc * Default URI for first level XML dynamic block(s) which do not * have an URI in their definition in template file. This * optional parameter can be null. * @param keyValuesList * List of key-value pairs used to set values to the JDynamiTe * variables contained in the input template. Each key-value pair * will be passed to the * {@link JDynamiTe#setVariable(String, String)} method. * @param verbose * If true, print on stderr output some information messages * during document processing. * @return If the inputStreamTemplateFile can be read and analysed, this method * returns the JDynamiTe object used to process the template * document.
* Use then the {@link JDynamiTe#toString()} method on this returned * object to get the parsing result (i.e. the populated output * document).
* If the inputTemplateFile is undefined or can not be read, this * method returns null. * @see JDynamiTe#setInput(String) * @see JDynamiTe#setVariable(String, String) */ public JDynamiTe run(InputStream inputStreamTemplateFile, String defaultRootXMLInputDoc, Hashtable keyValuesList, boolean verbose) { inputStreamTemplateFileOpt = inputStreamTemplateFile; inputTemplateFileOpt = ""; defaultRootXMLdoc = defaultRootXMLInputDoc; if (keyValuesList != null) keyValuesOpt.putAll(keyValuesList); verboseOpt = verbose; return run(true); } /** * Processes the input template file and then produces the output result. It * is assumed that the input template file has already been read and * analysed by calling either {@link #run(String, String, Hashtable, boolean)} * method, or {@link #run(InputStream, String, Hashtable, boolean)} method.
* This method is the same than the * {@link #run(String, String, Hashtable, boolean)} method, except that * there is no call to the {@link JDynamiTe#setInput(String)} or * {@link JDynamiTe#setInput(InputStream)} method.
* Call this method if the input template file does not change from one call * to another, while you need to change other parameters such as Variable * key-value list.
* * @param defaultRootXMLInputDoc * Default URI for first level XML dynamic block(s) which do not * have an URI in their definition in template file. This * optional parameter can be null. * @param keyValuesList * keyValuesList List of key-value pairs used to set values to * the JDynamiTe variables contained in the input template. Each * key-value pair will be passed to the * {@link JDynamiTe#setVariable(String, String)} method. * @param verbose * If true, print on stderr output some information messages * during document processing. * @return This method returns null if no input template file was defined by * a previous call to the * {@link #run(String, String, Hashtable, boolean)} method.
* Otherwise this method returns the JDynamiTe object used to * process the template document.
* Use then the {@link JDynamiTe#toString()} method on this returned * object to get the parsing result (i.e. the populated output * document).
* If the inputTemplateFile is undefined or can not be read, this * method returns null. */ public JDynamiTe run(String defaultRootXMLInputDoc, Hashtable keyValuesList, boolean verbose) { defaultRootXMLdoc = defaultRootXMLInputDoc; if (keyValuesList != null) keyValuesOpt.putAll(keyValuesList); verboseOpt = verbose; return run(false); } /** * Processes the input template file and then produces the output result. * This method uses a JDynamiTe object to process the input template file * and then produce the output result.
* 1) processing all "simple" JDynamiTe Variables, by calling * {@link JDynamiTe#setVariable(String, String)} method for each key-value * pair.
* 2) processing recursively all XML Dynamic blocks, by calling the * {@link JDynamiTe#parseXMLDynElem()} method. * * @param doSetInput * If true, the previously defined input template file name will * be used to call the {@link JDynamiTe#setInput(String)} method.
* If false, the current template is used, after clearing all * variables. * * @return If the inputTemplateFile is undefined or can not be read, this * method returns null.
* Otherwise this method returns the JDynamiTe object used to * process the template document. */ private JDynamiTe run(boolean doSetInput) { JDynamiTe.setVerbose(verboseOpt); if (inputTemplateFileOpt.equals("") && inputStreamTemplateFileOpt == null) { System.err.println("Error: undefined input template file !"); return null; } if (doSetInput) { if (verboseOpt) System.err.println("Calling jDyn.setInput..."); try { if (inputStreamTemplateFileOpt != null) jDyn.setInput(inputStreamTemplateFileOpt); else jDyn.setInput(inputTemplateFileOpt); } catch (Exception e) { System.err.println(e.getMessage()); return null; } undefinedInputXMLElements.clear(); } else { jDyn.resetAll(); restoreUndefinedXMLInput(); } if (verboseOpt) System.err.println("XMLdefaultRootDoc=" + ((defaultRootXMLdoc != null) ? defaultRootXMLdoc : "null")); if (getDefOpt) { String totalDef = jDyn.getDefinition(0); System.err.println("\n----- Template Definition -----\n\n" + totalDef + "\n-----\n"); } if (getKeysOpt) { System.err.println("\n===== keys =====\n"); Enumeration keys = jDyn.getVariableKeys(); while (keys.hasMoreElements()) { System.err.println("[" + keys.nextElement() + "]"); } System.err.println("\n=====\n"); } processVariables(); processDynElem(); parseXMLDynElem(); ///processXML___test__manuel(); jDyn.parse(); return jDyn; } private void parseXMLDynElem() { jDyn.parseXMLDynElem(); } private void processDynElem() { Enumeration keyDynElems = jDyn.getDynElemenKeys(); while (keyDynElems.hasMoreElements()) { String elemName = keyDynElems.nextElement(); if (jDyn.isXMLDynElement(elemName)) { if (defaultRootXMLdoc != null) { // Set an "XMLInput" for all "first level" XML dyn. elem which have none. IDynamicElement xmlDynElem = jDyn.getDynElem(elemName); if (xmlDynElem.getFatherDynElem() == jDyn) { // Parent is jDyn so this is a first level element. String xmlInput = xmlDynElem.getXMLInput(); if (xmlInput == DefaultAnalyser.XML_UNDEFINED_INPUT) { if (verboseOpt) System.err.println("Setting default XML input \"" + defaultRootXMLdoc + "\" for \"" + elemName + "\" block"); jDyn.setXMLInput(elemName, defaultRootXMLdoc); undefinedInputXMLElements.add(xmlDynElem); } else { if (verboseOpt) System.err.println("XML input for \"" + elemName + "\" block = " + xmlInput); } } } } else if (jDyn != jDyn.getDynElem(elemName)) { // parse all non XML blocks, except the "root elem." (i.e jDyn itself) /* In fact: can suppress this code block because it can not do anything: it is useless (without input data set by setVariable method) to iterate on these blocks ! */ if (verboseOpt) System.err.println("Parsing dyn. elem. \"" + elemName + "\""); jDyn.parseDynElem(elemName); } } } private void restoreUndefinedXMLInput() { for (IDynamicElement xmlElem : undefinedInputXMLElements) { xmlElem.setXMLInput(DefaultAnalyser.XML_UNDEFINED_INPUT); } } private void processVariables() { Enumeration keyVars = keyValuesOpt.keys(); while (keyVars.hasMoreElements()) { String key = keyVars.nextElement(); String value = keyValuesOpt.get(key); jDyn.setVariable(key, value); if (verboseOpt) System.err.println("Setting value \"" + value + "\" for variable \"" + key + '\"'); } // Set __INPUT_TEMPLATE__ as "special" variable if not already set by the user. String inputTemplVar = jDyn.getVariable(JDynTool.INPUT_TEMPLATE_PATH_VAR_TAG); if (inputTemplVar != null && inputTemplVar.equals("")) { // Set default value for __INPUT_TEMPLATE__ : relative to exampleRootPath or not ? to be improved ... jDyn.setVariable(JDynTool.INPUT_TEMPLATE_PATH_VAR_TAG, /*exampleRootPath + /"input/"*/ new File(inputTemplateFileOpt).getName()); if (verboseOpt) System.err.println("Setting value \"" + inputTemplateFileOpt + "\" for special variable \"" + JDynTool.INPUT_TEMPLATE_PATH_VAR_TAG + '\"'); } } private String getInputTemplateFileName() { return inputTemplateFileOpt; } private void setInputTemplateFileName(String inputTemplateFile) { inputTemplateFileOpt = inputTemplateFile; } /* private InputStream getInputStreamTemplateFile() { return inputStreamTemplateFileOpt; } */ private void setInputStreamTemplateFile(InputStream inputStreamTemplateFile) { inputStreamTemplateFileOpt = inputStreamTemplateFile; } private static void usage() { System.err.println("\nUsage: JDynTool --template jdyn-template-file [--definition] [--keys] [--verbose] [--XMLdefaultRootDoc URI] [-D = ...]\n"); System.err.println(" --template jdyn-file\n -t jdyn-file \t specify JDynamiTe input template file"); System.err.println(" --definition\n -d \t\t\t output on stderr the JDynamiTe input template file structure definition (as interpreted by JDynamiTe)"); System.err.println(" --keys\n -k \t\t\t output on stderr the list of JDynamiTe Variable tags (keys) found in the JDynamiTe input template file"); System.err.println(" --verbose\n -v \t\t\t output on stderr some information messages during document processing"); System.err.println(" --XMLdefaultRootDoc URI-path\n -X URI-path \t\t Default URI/path for first level XML dynamic blocks which do not have an URI in their definition in template file"); System.err.println(" -D = ...\t List of key-value pairs used to set values to the JDynamiTe variables contained in the input template"); } private boolean processOpt(int opt, Getopt g) { //System.out.println("JDynTool.processOpt(), opt=" + (char)opt); boolean optValid = true; String arg; switch (opt) { case 'd': getDefOpt = true; break; case 'k': getKeysOpt = true; break; case 't': arg = g.getOptarg(); inputTemplateFileOpt = arg; break; case 'X': arg = g.getOptarg(); defaultRootXMLdoc = arg; break; case 'D': arg = g.getOptarg(); String[] subargs = arg.split("=", 2); //System.err.println("key=" + subargs[0] + ", value=" + subargs[1]); keyValuesOpt.put(subargs[0], subargs[1]); break; case 'h': optValid = false; case 'v': verboseOpt = true; break; default: optValid = false; } return optValid; } private boolean parseCommandLine(String[] args) { StringBuffer longOption = new StringBuffer(); LongOpt[] longopts = new LongOpt[5]; longopts[0] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v'); longopts[1] = new LongOpt("definition", LongOpt.NO_ARGUMENT, null, 'd'); longopts[2] = new LongOpt("keys", LongOpt.NO_ARGUMENT, null, 'k'); longopts[3] = new LongOpt("template", LongOpt.REQUIRED_ARGUMENT, longOption, 't'); longopts[4] = new LongOpt("XMLdefaultRootDoc", LongOpt.REQUIRED_ARGUMENT, longOption, 'X'); Getopt g = new Getopt("JDynTool", args, "vhdkt:D:X:", longopts); // int c, opt; boolean optOK = true; while ((c = g.getopt()) != -1) { switch (c) { case 0: opt = (new Integer(longOption.toString())).intValue(); break; case '?': opt = -1; optOK = false; break; // getopt() already printed an error default: opt = c; } if (opt != -1) if (!processOpt(opt, g)) optOK = false; } //System.err.println("inputTemplateFile=" + inputTemplateFile + ", inputXMLFile=" + inputXMLFile); if (!optOK || inputTemplateFileOpt.equals("")) { return false; } return true; } /** * @param args Parameters for Command line invocation. *

* Usage:
*
{@code JDynTool --template jdyn-template-file [--definition] [--keys] [--verbose] [--XMLdefaultRootDoc URI] [-D = ...]}

{@code --template jdyn-file}
{@code -t jdyn-file}
Specify JDynamiTe input template file.

{@code --definition}
{@code -d}
Output on stderr the JDynamiTe input template file structure definition (as interpreted by JDynamiTe).

{@code --keys}
{@code -k}
Output on stderr the list of JDynamiTe Variable tags (keys) found in the JDynamiTe input template file.

{@code --verbose}
{@code -v}
Output on stderr some information messages during document processing.

{@code --XMLdefaultRootDoc URI-path}
{@code -X URI-path}
Default URI/path for first level XML dynamic blocks which do not have an URI-path in their definition in template file.

{@code -D = ...}
List of key-value pairs used to set values to the JDynamiTe variables contained in the input template}

*/ public static void main(String[] args) { JDynTool jDynTool = new JDynTool(); if (!jDynTool.parseCommandLine(args)) { usage(); return; } JDynamiTe jDyn = jDynTool.run(true); if (jDyn != null) System.out.println(jDyn.toString()); } // Test via InputStream protected static void mainTestInputStream(String[] args) { JDynTool jDynTool = new JDynTool(); if (!jDynTool.parseCommandLine(args)) { usage(); return; } try { InputStream istream = new FileInputStream(jDynTool.getInputTemplateFileName()); jDynTool.setInputStreamTemplateFile(istream); jDynTool.setInputTemplateFileName(""); JDynamiTe jDyn = jDynTool.run(true); if (jDyn != null) System.out.println(jDyn.toString()); istream.close(); } catch (Exception e) { e.printStackTrace(); return; } } }