home *** CD-ROM | disk | FTP | other *** search
/ LG Super CD / LG Super CD.iso / hack / azureus_2.5.0.4a_win32.setup.exe / plugins / azplugins / azplugins_2.1.4.jar / HTML / Template.java < prev   
Encoding:
Java Source  |  2007-01-26  |  34.0 KB  |  1,087 lines

  1. /*
  2.  *      HTML.Template:  A module for using HTML Templates with java
  3.  *
  4.  *      Copyright (c) 2002 Philip S Tellis (philip.tellis@iname.com)
  5.  *
  6.  *      This module is free software; you can redistribute it
  7.  *      and/or modify it under the terms of either:
  8.  *
  9.  *      a) the GNU General Public License as published by the Free
  10.  *      Software Foundation; either version 1, or (at your option)
  11.  *      any later version, or
  12.  *
  13.  *      b) the "Artistic License" which comes with this module.
  14.  *
  15.  *      This program is distributed in the hope that it will be
  16.  *      useful, but WITHOUT ANY WARRANTY; without even the implied
  17.  *      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  18.  *      PURPOSE.  See either the GNU General Public License or the
  19.  *      Artistic License for more details.
  20.  *
  21.  *      You should have received a copy of the Artistic License
  22.  *      with this module, in the file ARTISTIC.  If not, I'll be
  23.  *      glad to provide one.
  24.  *
  25.  *      You should have received a copy of the GNU General Public
  26.  *      License along with this program; if not, write to the Free
  27.  *      Software Foundation, Inc., 59 Temple Place, Suite 330,
  28.  *      Boston, MA 02111-1307 USA
  29.  *
  30.  *      Modified by Tobias Minich, Aug 2003
  31.  *      Unmodified form is available from http://html-tmpl-java.sourceforge.net
  32.  */
  33.  
  34. package HTML;
  35. import java.util.*;
  36. import java.io.*;
  37. import HTML.Tmpl.Element.*;
  38. import HTML.Tmpl.Parsers.*;
  39. import HTML.Tmpl.Util;
  40. import HTML.Tmpl.Filter;
  41.  
  42. /**
  43.  * Use HTML Templates with java.
  44.  * <p>
  45.  * The HTML.Template class allows you to use HTML Templates from within
  46.  * your java programs.  It makes it possible to change the look of your
  47.  * servlets without having to recompile them.  Use HTML.Template to
  48.  * separate code from presentation in your servlets.
  49.  * <p>
  50.  * <pre>
  51.  *    Hashtable args = new Hashtable();
  52.  *    args.put("filename", "my_template.tmpl");
  53.  *
  54.  *    Template t = new Template(args);
  55.  *
  56.  *    t.setParam("title", "The HTML Template package");
  57.  *    t.printTo(response.getWriter());
  58.  * </pre>
  59.  * <p>
  60.  * HTML.Template is based on the perl module HTML::Template by Sam Tregar
  61.  *
  62.  * @author    Philip S Tellis
  63.  * @version    0.1.2
  64.  */
  65. public class Template {
  66.   private If __template__ = new If("__template__");
  67.   private Hashtable params = new Hashtable();
  68.   
  69.   private boolean dirty = true;
  70.   
  71.   private boolean strict = true;
  72.   private boolean die_on_bad_params = false;
  73.   private boolean global_vars = false;
  74.   private boolean case_sensitive = false;
  75.   private boolean loop_context_vars = false;
  76.   private boolean debug = false;
  77.   private boolean no_includes = false;
  78.   private boolean search_path_on_include = false;
  79.   private int max_includes = 11;
  80.   private String filename = null;
  81.   private String scalarref = null;
  82.   private String [] arrayref = null;
  83.   private String [] path = null;
  84.   private Reader filehandle = null;
  85.   private Filter [] filters = null;
  86.   
  87.   private Stack elements = new Stack();
  88.   private Parser parser;
  89.   
  90.   // begin - Added August 2003 by Tobias Minich
  91.   public List vars = new LinkedList();
  92.   // end - Added August 2003
  93.   
  94.   /**
  95.    * Initialises a new HTML.Template object with the contents of
  96.    * the given file.
  97.    *
  98.    * @param filename            a string containing the name of
  99.    *                    the file to be used as a
  100.    *                    template.  This may be an
  101.    *                    absolute or relative path to a
  102.    *                    template file.
  103.    *
  104.    * @throws FileNotFoundException    If the file specified does not
  105.    *                    exist.
  106.    * @throws IllegalStateException    If <tmpl_include> is
  107.    *                    used when no_includes is in
  108.    *                    effect.
  109.    * @throws IOException            If an input or output Exception
  110.    *                    occurred while reading the
  111.    *                    template.
  112.    *
  113.    * @deprecated No replacement.  You should use either
  114.    *                {@link #Template(Object [])} or
  115.    *                {@link #Template(Hashtable)}
  116.    */
  117.   public Template(String filename)
  118.   throws FileNotFoundException,
  119.   IllegalStateException,
  120.   IOException {
  121.     this.filename = filename;
  122.     init();
  123.   }
  124.   
  125.   /**
  126.    * Initialises a new Template object, using the name/value
  127.    * pairs passed as default values.
  128.    * <p>
  129.    * The parameters passed may be any combination of filename,
  130.    * scalarref, arrayref, path, case_sensitive, loop_context_vars,
  131.    * strict, die_on_bad_params, global_vars, max_includes,
  132.    * no_includes, search_path_on_include and debug.
  133.    * Each with its own value.  Any one of filename, scalarref or
  134.    * arrayref must be passed.
  135.    * <p>
  136.    * Eg:
  137.    * <pre>
  138.    *    String [] template_init = {
  139.    *        "filename",  "my_template.tmpl",
  140.    *        "case_sensitive", "true",
  141.    *        "max_includes",   "5"
  142.    *    };
  143.    *
  144.    *      Template t = new Template(template_init);
  145.    * </pre>
  146.    * <p>
  147.    * The above code creates a new Template object, initialising
  148.    * its input file to my_template.tmpl, turning on case_sensitive
  149.    * parameter matching, and restricting maximum depth of includes
  150.    * to five.
  151.    * <p>
  152.    * Parameter values that take boolean values may either be a String
  153.    * containing the words true/false, or the Boolean values Boolean.TRUE
  154.    * and Boolean.FALSE.  Numeric values may be Strings, or Integers.
  155.    *
  156.    * @since 0.0.8
  157.    *
  158.    * @param args        an array of name/value pairs to initialise
  159.    *            this template with.  Valid values for
  160.    *            each element may be:
  161.    * @param filename    [Required] a String containing the path to a
  162.    *            template file
  163.    * @param scalarref    [Required] a String containing the entire
  164.    *            template as its contents
  165.    * @param arrayref    [Required] an array of lines that make up
  166.    *            the template
  167.    * @param path        [Optional] an array of Strings specifying
  168.    *            the directories in which to look for the
  169.    *            template file.  If not specified, the current
  170.    *            working directory is used.  If specified,
  171.    *            only the directories in this array are used.
  172.    *            If you want the current directory searched,
  173.    *            include "." in the path.
  174.    *            <p>
  175.    *            If you have only a single path, it can be a
  176.    *            plain String instead of a String array.
  177.    *            <p>
  178.    *            This is effective only for the template file,
  179.    *            and not for included files, but see
  180.    *            search_path_on_include for how to change that.
  181.    * @param case_sensitive    [Optional] specifies whether parameter
  182.    *            matching is case sensitive or not.  A value
  183.    *            of "false", "0" or "" is considered false.
  184.    *            All other values are true.
  185.    *            <p>
  186.    *            Default: false
  187.    * @param loop_context_vars    [Optional] when set to true four loop
  188.    *             context variables are made available inside a
  189.    *            loop: <code>__FIRST__, __LAST__, __INNER__, __ODD__, __COUNTER__</code>.
  190.    *            They can be used with <code><TMPL_IF></code>,
  191.    *            <code><TMPL_UNLESS></code> and <code><TMPL_ELSE></code> to
  192.    *            control how a loop is output. Example:
  193.    *            <pre>
  194.    *        <TMPL_LOOP NAME="FOO">
  195.    *           <TMPL_IF NAME="__FIRST__">
  196.    *             This only outputs on the first pass.
  197.    *           </TMPL_IF>
  198.    *
  199.    *           <TMPL_IF NAME="__ODD__">
  200.    *             This outputs on the odd passes.
  201.    *           </TMPL_IF>
  202.    *
  203.    *           <TMPL_UNLESS NAME="__ODD__">
  204.    *             This outputs on the even passes.
  205.    *           </TMPL_IF>
  206.    *
  207.    *           <TMPL_IF NAME="__INNER__">
  208.    *             This outputs on passes that are
  209.    *        neither first nor last.
  210.    *           </TMPL_IF>
  211.    *
  212.    *           <TMPL_IF NAME="__LAST__">
  213.    *             This only outputs on the last pass.
  214.    *           <TMPL_IF>
  215.    *        </TMPL_LOOP>
  216.    *            </pre>
  217.    *            <p>
  218.    *            NOTE: A loop with only a single pass will get
  219.    *            both <code>__FIRST__</code> and <code>__LAST__</code>
  220.    *            set to true, but not <code>__INNER__</code>.
  221.    *            <p>
  222.    *            Default: false
  223.    * @param strict    [Optional] if set to false the module will
  224.    *            allow things that look like they might be
  225.    *            TMPL_* tags to get by without throwing
  226.    *            an exception.  Example:
  227.    *            <pre>
  228.    *          <TMPL_HUH NAME=ZUH>
  229.    *            </pre>
  230.    *            <p>
  231.    *            Would normally cause an error, but if you
  232.    *            create the Template with strict == 0,
  233.    *            HTML.Template will ignore it.
  234.    *            <p>
  235.    *            Default: true
  236.    * @param die_on_bad_params        [Optional] if set to true
  237.    *            the module will complain if you try to set
  238.    *            tmpl.setParam("param_name", "value") and
  239.    *            param_name doesn't exist in the template.
  240.    *            <p>
  241.    *            This effect doesn't descend into loops.
  242.    *            <p>
  243.    *            Default: false (may change in later versions)
  244.    * @param global_vars    [Optional] normally variables declared outside
  245.    *            a loop are not available inside a loop.  This
  246.    *            option makes TMPL_VARs global throughout
  247.    *            the template.  It also affects TMPL_IF and TMPL_UNLESS.
  248.    *            <pre>
  249.    *        <p>This is a normal variable: <TMPL_VAR NORMAL>.</p>
  250.    *
  251.    *        <TMPL_LOOP NAME="FROOT_LOOP>
  252.    *           Here it is inside the loop: <TMPL_VAR NORMAL>
  253.    *        </TMPL_LOOP>
  254.    *            </pre>
  255.    *            <p>
  256.    *            Normally this wouldn't work as expected, since
  257.    *            <TMPL_VAR NORMAL>'s value outside the loop
  258.    *            isn't available inside the loop.
  259.    *            <p>
  260.    *            Default: false (may change in later versions)
  261.    * @param max_includes    [Optional] specifies the maximum depth that
  262.    *            includes can reach.  Including files to a
  263.    *            depth greater than this value causes an error
  264.    *            message to be displayed.  Set to 0 to disable
  265.    *            this protection.
  266.    *            <p>
  267.    *            Default: 10
  268.    * @param no_includes    [Optional] If set to true, disallows the
  269.    *            <TMPL_INCLUDE> tag in the template
  270.    *            file.  This can be used to make opening
  271.    *            untrusted templates slightly less dangerous.
  272.    *            <p>
  273.    *            Default: false
  274.    * @param search_path_on_include    [Optional] if set, then the
  275.    *            path is searched for included files as well
  276.    *            as the template file.  See the path parameter
  277.    *            for more information.
  278.    *            <p>
  279.    *            Default: false
  280.    * @param debug        [Optional] setting this option to true causes
  281.    *            HTML.Template to print random error messages
  282.    *            to STDERR.
  283.    *
  284.    * @throws ArrayIndexOutOfBoundsException    If an odd number of
  285.    *                    parameters is passed.
  286.    * @throws FileNotFoundException    If the file specified does not
  287.    *                    exist or no filename is passed.
  288.    * @throws IllegalArgumentException    If an unknown parameter is
  289.    *                    passed.
  290.    * @throws IllegalStateException    If <tmpl_include> is
  291.    *                    used when no_includes is in
  292.    *                    effect.
  293.    * @throws IOException            If an input or output Exception
  294.    *                    occurred while reading the
  295.    *                    template.
  296.    */
  297.   public Template(Object [] args)
  298.   throws ArrayIndexOutOfBoundsException,
  299.   FileNotFoundException,
  300.   IllegalArgumentException,
  301.   IllegalStateException,
  302.   IOException
  303.   
  304.   {
  305.     if(args.length%2 != 0)
  306.       throw new ArrayIndexOutOfBoundsException("odd number " +
  307.       "of arguments passed");
  308.     
  309.     for(int i=0; i<args.length; i+=2) {
  310.       parseParam((String)args[i], args[i+1]);
  311.     }
  312.     
  313.     init();
  314.   }
  315.   
  316.   /**
  317.    * Initialises a new Template object, using the values in the
  318.    * Hashtable args as defaults.
  319.    * <p>
  320.    * The parameters passed are the same as in the Template(Object [])
  321.    * constructor. Each with its own value.  Any one of filename,
  322.    * scalarref or arrayref must be passed.
  323.    * <p>
  324.    * Eg:
  325.    * <pre>
  326.    *    Hashtable args = new Hashtable();
  327.    *    args.put("filename", "my_template.tmpl");
  328.    *    args.put("case_sensitive", "true");
  329.    *    args.put("loop_context_vars", Boolean.TRUE);
  330.    *    // args.put("max_includes", "5");
  331.    *    args.put("max_includes", new Integer(5));
  332.    *
  333.    *    Template t = new Template(args);
  334.    * </pre>
  335.    * <p>
  336.    * The above code creates a new Template object, initialising
  337.    * its input file to my_template.tmpl, turning on case_sensitive
  338.    * parameter matching, and the loop context variables __FIRST__,
  339.    * __LAST__, __ODD__ and __INNER__, and restricting maximum depth of
  340.    * includes to five.
  341.    * <p>
  342.    * Parameter values that take boolean values may either be a String
  343.    * containing the words true/false, or the Boolean values Boolean.TRUE
  344.    * and Boolean.FALSE.  Numeric values may be Strings, or Integers.
  345.    *
  346.    * @since 0.0.10
  347.    *
  348.    * @param args        a Hashtable of name/value pairs to initialise
  349.    *            this template with.  Valid values are the same
  350.    *            as in the Template(Object []) constructor.
  351.    *
  352.    * @throws FileNotFoundException    If the file specified does not
  353.    *                    exist or no filename is passed.
  354.    * @throws IllegalArgumentException    If an unknown parameter is
  355.    *                    passed.
  356.    * @throws IllegalStateException    If <tmpl_include> is
  357.    *                    used when no_includes is in
  358.    *                    effect.
  359.    * @throws IOException            If an input or output Exception
  360.    *                    occurred while reading the
  361.    *                    template.
  362.    *
  363.    * @see #Template(Object [])
  364.    */
  365.   public Template(Hashtable args)
  366.   throws FileNotFoundException,
  367.   IllegalArgumentException,
  368.   IllegalStateException,
  369.   IOException
  370.   
  371.   {
  372.     Enumeration e = args.keys();
  373.     while(e.hasMoreElements()) {
  374.       String key = (String)e.nextElement();
  375.       Object value = args.get(key);
  376.       
  377.       parseParam(key, value);
  378.     }
  379.     
  380.     init();
  381.   }
  382.   
  383.   /**
  384.    * Prints the parsed template to the provided PrintWriter.
  385.    *
  386.    * @param out    the PrintWriter that this template will be printed
  387.    *        to
  388.    */
  389.   public void printTo(PrintWriter out) {
  390.     out.print(output());
  391.   }
  392.   
  393.   /**
  394.    * Returns the parsed template as a String.
  395.    *
  396.    * @return    a string containing the parsed template
  397.    */
  398.   public String output() {
  399.     return __template__.parse(params);
  400.   }
  401.   
  402.   // begin - Added August 2003 by Tobias Minich
  403.   /**
  404.    * Clears the set parameters.
  405.    *
  406.    * @author Tobias Minich
  407.    */
  408.   public void clearParams() {
  409.     if (!params.isEmpty()) {
  410.       params.clear();
  411.       params.put("__template__","true");
  412.       dirty = true;
  413.     }
  414.   }
  415.   // end - Added August 2003
  416.   
  417.   /**
  418.    * Sets the values of parameters in this template from a Hashtable.
  419.    *
  420.    * @param params    a Hashtable containing name/value pairs for
  421.    *            this template.  Keys in this hashtable must
  422.    *            be Strings and values may be either Strings
  423.    *            or Vectors.
  424.    *            <p>
  425.    *            Parameter names are currently not case
  426.    *            sensitive.
  427.    *            <p>
  428.    *            Parameter names can contain only letters,
  429.    *            digits,    ., /, +, - and _ characters.
  430.    *            <p>
  431.    *            Parameter names starting and ending with
  432.    *            a double underscore are not permitted.
  433.    *            eg: <code>__myparam__</code> is illegal.
  434.    *
  435.    * @return        the number of parameters actually set.
  436.    *            Illegal parameters will not be set, but
  437.    *            no error/exception will be thrown.
  438.    */
  439.   public int setParams(Hashtable params) {
  440.     if(params == null || params.isEmpty())
  441.       return 0;
  442.     int count=0;
  443.     for(Enumeration e = params.keys(); e.hasMoreElements();) {
  444.       Object key = e.nextElement();
  445.       if(key.getClass().getName().endsWith(".String")) {
  446.         Object value = params.get(key);
  447.         try {
  448.           setParam((String)key, value);
  449.           count++;
  450.         } catch (Exception pe) {
  451.           // key was not a String or Vector
  452.           // or key was null
  453.           // don't increment count
  454.         }
  455.       }
  456.     }
  457.     if(count>0) {
  458.       dirty=true;
  459.       Util.debug_print("Now dirty: set params");
  460.     }
  461.     
  462.     return count;
  463.   }
  464.   
  465.   /**
  466.    * Sets a single scalar parameter in this template.
  467.    *
  468.    * @param name    a String containing the name of this parameter.
  469.    *        Parameter names are currently not case sensitive.
  470.    * @param value    a String containing the value of this parameter
  471.    *
  472.    * @return                the value of the parameter set
  473.    * @throws IllegalArgumentException     if the parameter name contains
  474.    *                    illegal characters
  475.    * @throws NullPointerException     if the parameter name is null
  476.    *
  477.    * @see #setParams(Hashtable)
  478.    */
  479.   public String setParam(String name, String value)
  480.   throws IllegalArgumentException, NullPointerException {
  481.     try {
  482.       return (String)setParam(name, (Object)value);
  483.     } catch(ClassCastException iae) {
  484.       return null;
  485.     }
  486.   }
  487.   
  488.   /**
  489.    * Sets a single Integer parameter in this template.
  490.    *
  491.    * @param name    a String containing the name of this parameter.
  492.    *        Parameter names are currently not case sensitive.
  493.    * @param value    an Integer containing the value of this parameter
  494.    *
  495.    * @return                the value of the parameter set
  496.    * @throws IllegalArgumentException     if the parameter name contains
  497.    *                    illegal characters
  498.    * @throws NullPointerException     if the parameter name is null
  499.    *
  500.    * @see #setParams(Hashtable)
  501.    */
  502.   public Integer setParam(String name, Integer value)
  503.   throws IllegalArgumentException, NullPointerException {
  504.     try {
  505.       return (Integer)setParam(name, (Object)value);
  506.     } catch(ClassCastException iae) {
  507.       return null;
  508.     }
  509.   }
  510.   
  511.   /**
  512.    * Sets a single int parameter in this template.
  513.    *
  514.    * @param name    a String containing the name of this parameter.
  515.    *        Parameter names are currently not case sensitive.
  516.    * @param value    an int containing the value of this parameter
  517.    *
  518.    * @return                the value of the parameter set
  519.    * @throws IllegalArgumentException     if the parameter name contains
  520.    *                    illegal characters
  521.    * @throws NullPointerException     if the parameter name is null
  522.    *
  523.    * @see #setParams(Hashtable)
  524.    */
  525.   public int setParam(String name, int value)
  526.   throws IllegalArgumentException, NullPointerException {
  527.     return setParam(name, new Integer(value)).intValue();
  528.   }
  529.   
  530.   /**
  531.    * Sets a single boolean parameter in this template.
  532.    *
  533.    * @param name    a String containing the name of this parameter.
  534.    *        Parameter names are currently not case sensitive.
  535.    * @param value    a boolean containing the value of this parameter
  536.    *
  537.    * @return                the value of the parameter set
  538.    * @throws IllegalArgumentException     if the parameter name contains
  539.    *                    illegal characters
  540.    * @throws NullPointerException     if the parameter name is null
  541.    *
  542.    * @see #setParams(Hashtable)
  543.    */
  544.   public boolean setParam(String name, boolean value)
  545.   throws IllegalArgumentException, NullPointerException {
  546.     return setParam(name, new Boolean(value)).booleanValue();
  547.   }
  548.   
  549.   /**
  550.    * Sets a single Boolean parameter in this template.
  551.    *
  552.    * @param name    a String containing the name of this parameter.
  553.    *        Parameter names are currently not case sensitive.
  554.    * @param value    a Boolean containing the value of this parameter
  555.    *
  556.    * @return                the value of the parameter set
  557.    * @throws IllegalArgumentException     if the parameter name contains
  558.    *                    illegal characters
  559.    * @throws NullPointerException     if the parameter name is null
  560.    *
  561.    * @see #setParams(Hashtable)
  562.    */
  563.   public Boolean setParam(String name, Boolean value)
  564.   throws IllegalArgumentException, NullPointerException {
  565.     try {
  566.       return (Boolean)setParam(name, (Object)value);
  567.     } catch(ClassCastException iae) {
  568.       return null;
  569.     }
  570.   }
  571.   
  572.   /**
  573.    * Sets a single list parameter in this template.
  574.    *
  575.    * @param name    a String containing the name of this parameter.
  576.    *        Parameter names are not currently case sensitive.
  577.    * @param value    a Vector containing a list of Hashtables of parameters
  578.    *
  579.    * @return                the value of the parameter set
  580.    * @throws IllegalArgumentException     if the parameter name contains
  581.    *                    illegal characters
  582.    * @throws NullPointerException     if the parameter name is null
  583.    *
  584.    * @see #setParams(Hashtable)
  585.    */
  586.   public Vector setParam(String name, Vector value)
  587.   throws IllegalArgumentException, NullPointerException {
  588.     try {
  589.       return (Vector)setParam(name, (Object)value);
  590.     } catch(ClassCastException iae) {
  591.       return null;
  592.     }
  593.   }
  594.   
  595.   /**
  596.    * Returns a parameter from this template identified by the given name.
  597.    *
  598.    * @param name    a String containing the name of the parameter to be
  599.    *        returned.  Parameter names are not currently case
  600.    *        sensitive.
  601.    *
  602.    * @return    the value of the requested parameter.  If the parameter
  603.    *        is a scalar, the return value is a String, if the
  604.    *        parameter is a list, the return value is a Vector.
  605.    *
  606.    * @throws NoSuchElementException    if the parameter does not exist
  607.    *                    in the template
  608.    * @throws NullPointerException        if the parameter name is null
  609.    */
  610.   public Object getParam(String name)
  611.   throws NoSuchElementException, NullPointerException {
  612.     if(name == null)
  613.       throw new NullPointerException("name cannot be null");
  614.     if(!params.containsKey(name))
  615.       throw new NoSuchElementException(name +
  616.       " is not a parameter in this template");
  617.     
  618.     if(case_sensitive)
  619.       return params.get(name);
  620.     else
  621.       return params.get(name.toLowerCase());
  622.   }
  623.   
  624.   
  625.   private void parseParam(String key, Object value)
  626.   throws IllegalStateException {
  627.     if(key.equals("case_sensitive")) {
  628.       this.case_sensitive=boolify(value);
  629.       Util.debug_print("case_sensitive: "+value);
  630.     }
  631.     else if(key.equals("strict")) {
  632.       this.strict=boolify(value);
  633.       Util.debug_print("strict: "+value);
  634.     }
  635.     else if(key.equals("global_vars")) {
  636.       this.global_vars=boolify(value);
  637.       Util.debug_print("global_vars: "+value);
  638.     }
  639.     else if(key.equals("die_on_bad_params")) {
  640.       this.die_on_bad_params=boolify(value);
  641.       Util.debug_print("die_obp: "+value);
  642.     }
  643.     else if(key.equals("max_includes")) {
  644.       this.max_includes=intify(value)+1;
  645.       Util.debug_print("max_includes: "+value);
  646.     }
  647.     else if(key.equals("no_includes")) {
  648.       this.no_includes=boolify(value);
  649.       Util.debug_print("no_includes: "+value);
  650.     }
  651.     else if(key.equals("search_path_on_include")) {
  652.       this.search_path_on_include=boolify(value);
  653.       Util.debug_print("path_includes: "+value);
  654.     }
  655.     else if(key.equals("loop_context_vars")) {
  656.       this.loop_context_vars=boolify(value);
  657.       Util.debug_print("loop_c_v: "+value);
  658.     }
  659.     else if(key.equals("debug")) {
  660.       this.debug=boolify(value);
  661.       Util.debug=this.debug;
  662.       Util.debug_print("debug: "+value);
  663.     }
  664.     else if(key.equals("filename")) {
  665.       this.filename = (String)value;
  666.       Util.debug_print("filename: "+value);
  667.     }
  668.     else if(key.equals("scalarref")) {
  669.       this.scalarref = (String)value;
  670.       Util.debug_print("scalarref");
  671.     }
  672.     else if(key.equals("arrayref")) {
  673.       this.arrayref = (String [])value;
  674.       Util.debug_print("arrayref");
  675.     }
  676.     else if(key.equals("path")) {
  677.       if(value.getClass().getName().startsWith("["))
  678.         this.path = (String [])value;
  679.       else {
  680.         this.path = new String[1];
  681.         this.path[0] = (String)value;
  682.       }
  683.       Util.debug_print("path");
  684.       for(int j=0; j<this.path.length; j++)
  685.         Util.debug_print(this.path[j]);
  686.     }
  687.     else if(key.equals("filter")) {
  688.       if(value.getClass().getName().startsWith("["))
  689.         this.filters = (Filter [])value;
  690.       else {
  691.         this.filters = new Filter[1];
  692.         this.filters[0] = (Filter)value;
  693.       }
  694.       Util.debug_print("filters set: " + filters.length);
  695.     }
  696.     else if(key.equals("filehandle")) {
  697.       this.filehandle = (Reader)value;
  698.       Util.debug_print("filehandle");
  699.     }
  700.     else {
  701.       throw new IllegalArgumentException(
  702.       (String)key);
  703.     }
  704.     
  705.   }
  706.   
  707.   private void init()
  708.   throws FileNotFoundException,
  709.   IllegalStateException,
  710.   IOException {
  711.     if(this.filename == null &&
  712.     this.scalarref == null &&
  713.     this.arrayref == null &&
  714.     this.filehandle == null)
  715.       throw new FileNotFoundException("template filename required");
  716.     
  717.     Util.debug = this.debug;
  718.     
  719.     params.put("__template__", "true");
  720.     
  721.     String [] parser_params = {
  722.       "case_sensitive",     stringify(case_sensitive),
  723.       "strict",         stringify(strict),
  724.       "loop_context_vars",     stringify(loop_context_vars),
  725.       "global_vars",         stringify(global_vars)
  726.     };
  727.     
  728.     parser = new Parser(parser_params);
  729.     
  730.     if(this.filename != null)
  731.       read_file(filename);
  732.     else if(this.arrayref != null)
  733.       read_line_array(this.arrayref);
  734.     else if(this.scalarref != null)
  735.       read_line(this.scalarref);
  736.     else if(this.filehandle != null)
  737.       read_fh(this.filehandle);
  738.     
  739.     if(!elements.empty())
  740.       System.err.println("stack not empty");
  741.   }
  742.   
  743.   
  744.   private Element parseLine(String line, Element e)
  745.   throws FileNotFoundException,
  746.   IllegalStateException,
  747.   IOException,
  748.   EmptyStackException {
  749.     Vector parts;
  750.     
  751.     parts = parser.parseLine(line);
  752.     Util.debug_print("Items: " + parts.size());
  753.     
  754.     for(Enumeration pt = parts.elements(); pt.hasMoreElements();) {
  755.       Object o = pt.nextElement();
  756.       
  757.       if(o.getClass().getName().endsWith(".String")) {
  758.         if(((String)o).equals(""))
  759.           continue;
  760.         
  761.         e.add((String)o);
  762.         Util.debug_print("added: " +(String)o);
  763.         continue;
  764.       }
  765.       
  766.       // if we come here, then it is an element
  767.       
  768.       Properties p = (Properties)o;
  769.       String type=p.getProperty("type");
  770.       Util.debug_print("adding element: " + type);
  771.       
  772.       if(type.equals("include")) {
  773.         if(no_includes)
  774.           throw new IllegalStateException(
  775.           "<tmpl_include> not " +
  776.           "allowed when " +
  777.           "no_includes in effect"
  778.           );
  779.         if(max_includes == 0) {
  780.           throw new IndexOutOfBoundsException(
  781.           "include too deep");
  782.         } else {
  783.           // come here if positive
  784.           // or negative
  785.           elements.push(e);
  786.           read_file(p.getProperty("name"));
  787.         }
  788.       }
  789.       else if(type.equals("var")) {
  790.         String name = p.getProperty("name");
  791.         String escape = p.getProperty("escape");
  792.         String def = p.getProperty("default");
  793.         Util.debug_print("name: " + name);
  794.         Util.debug_print("escape: " + escape);
  795.         Util.debug_print("default: " + def);
  796.         e.add(new Var(name, escape, def));
  797.         // begin - Added August 2003 by Tobias Minich
  798.         vars.add(p.getProperty("name"));
  799.         // end - Added August 2003
  800.       }
  801.       else if(type.equals("else")) {
  802.         Util.debug_print("adding branch");
  803.         ((Conditional)e).addBranch();
  804.       }
  805.       // begin - Added October 2003 by Tobias Minich
  806.       else if(type.equals("case")) {
  807.         Util.debug_print("adding branch for select");
  808.         if (p.containsKey("name"))
  809.           ((Select)e).addBranch(p.getProperty("name"));
  810.         else
  811.           ((Select)e).addBranch(null);
  812.       }
  813.       // end - Added October 2003
  814.       else if(p.getProperty("close").equals("true")) {
  815.         Util.debug_print("closing tag");
  816.         if(!type.equals(e.Type()))
  817.           throw new EmptyStackException();
  818.         
  819.         e = (Element)elements.pop();
  820.       }
  821.       else {
  822.         // begin - Added August 2003 by Tobias Minich
  823.         if (type.equals("if") || type.equals("unless") || type.equals("loop") || type.equals("select"))
  824.           vars.add(p.getProperty("name"));
  825.         // end - Added August 2003
  826.  
  827.         Element t = parser.getElement(p);
  828.         e.add(t);
  829.         elements.push(e);
  830.         e=t;
  831.       }
  832.     }
  833.     return e;
  834.   }
  835.   
  836.   private void read_file(String filename)
  837.   throws FileNotFoundException,
  838.   IllegalStateException,
  839.   IOException,
  840.   EmptyStackException {
  841.     BufferedReader br=openFile(filename);
  842.     
  843.     String line;
  844.     
  845.     Element e = null;
  846.     if(elements.empty())
  847.       e = __template__;
  848.     else
  849.       e = (Element)elements.pop();
  850.     
  851.     max_includes--;
  852.     while((line=br.readLine()) != null) {
  853.       Util.debug_print("Line: " + line);
  854.       e = parseLine(line+"\n", e);
  855.     }
  856.     max_includes++;
  857.     
  858.     br.close();
  859.     br=null;
  860.     
  861.   }
  862.   
  863.   private void read_line_array(String [] lines)
  864.   throws FileNotFoundException,
  865.   IllegalStateException,
  866.   IOException,
  867.   EmptyStackException {
  868.     
  869.     Element e = __template__;
  870.     
  871.     max_includes--;
  872.     for(int i=0; i<lines.length; i++) {
  873.       Util.debug_print(lines[i]);
  874.       e = parseLine(lines[i], e);
  875.     }
  876.     max_includes++;
  877.   }
  878.   
  879.   private void read_line(String lines)
  880.   throws FileNotFoundException,
  881.   IllegalStateException,
  882.   IOException,
  883.   EmptyStackException {
  884.     
  885.     Element e = __template__;
  886.     
  887.     max_includes--;
  888.     StringTokenizer st = new StringTokenizer(lines, "\n");
  889.     while(st.hasMoreTokens()) {
  890.       String line = st.nextToken();
  891.       Util.debug_print(line);
  892.       e = parseLine(line+"\n", e);
  893.     }
  894.     max_includes++;
  895.   }
  896.   
  897.   private void read_fh(Reader handle)
  898.   throws FileNotFoundException,
  899.   IllegalStateException,
  900.   IOException,
  901.   EmptyStackException {
  902.     BufferedReader br=new BufferedReader(handle);
  903.     
  904.     String line;
  905.     
  906.     Element e = null;
  907.     if(elements.empty())
  908.       e = __template__;
  909.     else
  910.       e = (Element)elements.pop();
  911.     
  912.     max_includes--;
  913.     while((line=br.readLine()) != null) {
  914.       Util.debug_print("Line: " + line);
  915.       e = parseLine(line+"\n", e);
  916.     }
  917.     max_includes++;
  918.     
  919.     br.close();
  920.     br=null;
  921.     
  922.   }
  923.   
  924.   private Object setParam(String name, Object value)
  925.   throws ClassCastException,
  926.   NullPointerException,
  927.   IllegalArgumentException {
  928.     if(name==null)
  929.       throw new NullPointerException(
  930.       "parameter name cannot be null");
  931.     
  932.     
  933.     if(!Util.isNameChar(name)) {
  934.       throw new IllegalArgumentException("parameter name " +
  935.       "may only contain letters, digits, ., /, +, " +
  936.       "-, _");
  937.     }
  938.     
  939.     if(name.startsWith("__") && name.endsWith("__"))
  940.       throw new IllegalArgumentException("parameter name " +
  941.       "may not start and end with a double " +
  942.       "underscore");
  943.     
  944.     if(die_on_bad_params && !__template__.contains(name))
  945.       throw new IllegalArgumentException(name +
  946.       "is not a valid template entity");
  947.     
  948.     if(value==null)
  949.       value="";
  950.     
  951.     String type = value.getClass().getName();
  952.     if(type.indexOf(".") > 0)
  953.       type = type.substring(type.lastIndexOf(".")+1);
  954.     
  955.     String valid_types = ",String,Vector,Boolean,Integer,";
  956.     
  957.     if(valid_types.indexOf(type) < 0)
  958.       throw new ClassCastException(
  959.       "value is neither scalar nor list");
  960.     
  961.     name=case_sensitive?name:name.toLowerCase();
  962.     
  963.     if(!case_sensitive && type.equals("Vector")) {
  964.       value = lowerCaseAll((Vector)value);
  965.     }
  966.     
  967.     Util.debug_print("setting: " + name);
  968.     params.put(name, value);
  969.     
  970.     dirty=true;
  971.     return value;
  972.   }
  973.   
  974.   private static Vector lowerCaseAll(Vector v) {
  975.     Vector v2 = new Vector();
  976.     for(Enumeration e = v.elements(); e.hasMoreElements(); ) {
  977.       Hashtable h = (Hashtable)e.nextElement();
  978.       if(h == null) {
  979.         v2.addElement(h);
  980.         continue;
  981.       }
  982.       Hashtable h2 = new Hashtable();
  983.       for(Enumeration e2 = h.keys(); e2.hasMoreElements(); ) {
  984.         String key = (String)e2.nextElement();
  985.         Object value = h.get(key);
  986.         String value_type = value.getClass().getName();
  987.         Util.debug_print("to lower case: " + key + "(" + value_type + ")");
  988.         if(value_type.endsWith(".Vector"))
  989.           value = lowerCaseAll((Vector)value);
  990.         h2.put(key.toLowerCase(), value);
  991.       }
  992.       v2.addElement(h2);
  993.     }
  994.     return v2;
  995.   }
  996.   
  997.   private static boolean boolify(Object o) {
  998.     String s;
  999.     if(o.getClass().getName().endsWith(".Boolean"))
  1000.       return ((Boolean)o).booleanValue();
  1001.     else if(o.getClass().getName().endsWith(".String"))
  1002.       s = (String)o;
  1003.     else
  1004.       s = o.toString();
  1005.     
  1006.     if(s.equals("0") || s.equals("") || s.equals("false"))
  1007.       return false;
  1008.     return true;
  1009.   }
  1010.   
  1011.   private static int intify(Object o) {
  1012.     String s;
  1013.     if(o.getClass().getName().endsWith(".Integer"))
  1014.       return ((Integer)o).intValue();
  1015.     else if(o.getClass().getName().endsWith(".String"))
  1016.       s = (String)o;
  1017.     else
  1018.       s = o.toString();
  1019.     
  1020.     try {
  1021.       return Integer.parseInt(s);
  1022.     } catch(NumberFormatException nfe) {
  1023.       return 0;
  1024.     }
  1025.   }
  1026.   
  1027.   private static String stringify(boolean b) {
  1028.     if(b)
  1029.       return "1";
  1030.     else
  1031.       return "";
  1032.   }
  1033.   
  1034.   private BufferedReader openFile(String filename)
  1035.   throws FileNotFoundException {
  1036.     boolean add_path=true;
  1037.     
  1038.     if(!elements.empty() && !search_path_on_include)
  1039.       add_path=false;
  1040.     
  1041.     if(filename.startsWith("/"))
  1042.       add_path=false;
  1043.     
  1044.     if(this.path == null)
  1045.       add_path=false;
  1046.     
  1047.     Util.debug_print("open " + filename);
  1048.     if(!add_path)
  1049.       // begin - Added August 2003 by Tobias Minich
  1050.       //return new BufferedReader(new FileReader(filename));
  1051.     {
  1052.       if (filename.startsWith("RES:")) {
  1053.         InputStream is = ClassLoader.getSystemResourceAsStream(filename.substring(filename.indexOf(':')+1));
  1054.         if (is == null)
  1055.           throw new FileNotFoundException(filename);
  1056.         return new BufferedReader(new InputStreamReader(is));
  1057.       } else
  1058.         return new BufferedReader(new FileReader(filename));
  1059.     }
  1060.       // end - Added August 2003
  1061.     
  1062.     BufferedReader br=null;
  1063.     
  1064.     for(int i=0; i<this.path.length; i++) {
  1065.       try {
  1066.         Util.debug_print("trying " + this.path[i] + "/" + filename);
  1067.         // begin - Added August 2003 by Tobias Minich
  1068.         //br = new BufferedReader(new FileReader(this.path[i] + "/" + filename));
  1069.         if (this.path[i].startsWith("RES:")) {
  1070.           InputStream is = ClassLoader.getSystemResourceAsStream(this.path[i].substring(this.path[i].indexOf(':')+1) + "/" +filename);
  1071.           if (is != null)
  1072.           br = new BufferedReader(new InputStreamReader(is));
  1073.         } else
  1074.           br = new BufferedReader(new FileReader(this.path[i] + "/" + filename));
  1075.         // end - Added August 2003
  1076.         break;
  1077.       } catch (FileNotFoundException fnfe) {
  1078.       }
  1079.     }
  1080.     
  1081.     if(br == null)
  1082.       throw new FileNotFoundException(filename);
  1083.     
  1084.     return br;
  1085.   }
  1086. }
  1087.