View Javadoc

    1   /*
    2    * $Id: SimpleTemplateEngine.java,v 1.13 2004/12/08 22:45:33 spullara Exp $version Mar 8, 2004 2:11:00 AM $user Exp $
    3    *
    4    * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
    5    *
    6    * Redistribution and use of this software and associated documentation
    7    * ("Software"), with or without modification, are permitted provided that the
    8    * following conditions are met: 1. Redistributions of source code must retain
    9    * copyright statements and notices. Redistributions must also contain a copy
    10   * of this document. 2. Redistributions in binary form must reproduce the above
    11   * copyright notice, this list of conditions and the following disclaimer in
    12   * the documentation and/or other materials provided with the distribution. 3.
    13   * The name "groovy" must not be used to endorse or promote products derived
    14   * from this Software without prior written permission of The Codehaus. For
    15   * written permission, please contact info@codehaus.org. 4. Products derived
    16   * from this Software may not be called "groovy" nor may "groovy" appear in
    17   * their names without prior written permission of The Codehaus. "groovy" is a
    18   * registered trademark of The Codehaus. 5. Due credit should be given to The
    19   * Codehaus - http://groovy.codehaus.org/
    20   *
    21   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
    22   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    24   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
    25   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    27   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    28   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    31   * DAMAGE.
    32   *
    33   */
    34   package</strong<a href="../../> groovy/text/package-summary.html">> groovy.text;
    35
    36  import groovy.lang.Binding;
    37  import groovy.lang.GroovyShell;
    38  import groovy.lang.Script;
    39  import groovy.lang.Writable;
    40
    41  import java.io.BufferedReader;
    42  import java.io.IOException;
    43  import java.io.PrintWriter;
    44  import java.io.Reader;
    45  import java.io.StringWriter;
    46  import java.io.Writer;
    47  import java.util.Map;
    48
    49  import org.codehaus.groovy.control.CompilationFailedException;
    50  import org.codehaus.groovy.runtime.InvokerHelper;
    51
    52
    53  /***
    54   * This simple template engine uses JSP <% %> script and <%= %> expression syntax.  It also lets you use normal groovy expressions in
    55   * the template text much like the new JSP EL functionality.  The variable 'out' is bound to the writer that the template is being written to.
    56   *
    57   * @author sam
    58   */
    59  public class SimpleTemplateEngine extends TemplateEngine {
    60
    61      /* (non-Javadoc)
    62       * @see groovy.util.TemplateEngine#createTemplate(java.io.Reader)
    63       */
    64      public Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
    65          SimpleTemplate template = new SimpleTemplate();
    66          GroovyShell shell = new GroovyShell();
    67          String script = template.parse(reader);
    68          template.script = shell.parse(script);
    69          return template;
    70      }
    71
    72      private static class SimpleTemplate implements Template {
    73
    74          private Script script;
    75
    76          public Writable make() {
    77              return make(null);
    78          }
    79
    80          public Writable make(final Map map) {
    81              return new Writable() {
    82                  /***
    83                   * Write the template document with the set binding applied to the writer.
    84                   *
    85                   * @see groovy.lang.Writable#writeTo(java.io.Writer)
    86                   */
    87                  public Writer writeTo(Writer writer) throws IOException {
    88                      Binding binding;
    89                      if (map == null) binding = new Binding(); else binding = new Binding(map);
    90                      Script scriptObject = InvokerHelper.createScript(script.getClass(), binding);
    91                      PrintWriter pw = new PrintWriter(writer);
    92                      scriptObject.setProperty("out", pw);
    93                      scriptObject.run();
    94                      pw.flush();
    95                      return writer;
    96                  }
    97
    98                  /***
    99                   * Convert the template and binding into a result String.
    100                  *
    101                  * @see java.lang.Object#toString()
    102                  */
    103                 public String toString() {
    104                     try {
    105                         StringWriter sw = new StringWriter();
    106                         writeTo(sw);
    107                         return sw.toString();
    108                     } catch (Exception e) {
    109                         return e.toString();
    110                     }
    111                 }
    112             };
    113         }
    114
    115         /***
    116          * Parse the text document looking for <% or <%= and then call out to the appropriate handler, otherwise copy the text directly
    117          * into the script while escaping quotes.
    118          *
    119          * @param reader
    120          * @return
    121          * @throws IOException
    122          */
    123         private String parse(Reader reader) throws IOException {
    124             if (!reader.markSupported()) {
    125                 reader = new BufferedReader(reader);
    126             }
    127             StringWriter sw = new StringWriter();
    128             startScript(sw);
    129             boolean start = false;
    130             int c;
    131             while((c = reader.read()) != -1) {
    132                 if (c == '<') {
    133                     reader.mark(1);
    134                     c = reader.read();
    135                     if (c != '%') {
    136                         sw.write('<');
    137                         reader.reset();
    138                         continue;
    139                     } else {
    140                         reader.mark(1);
    141                         c = reader.read();
    142                         if (c == '=') {
    143                             groovyExpression(reader, sw);
    144                         } else {
    145                             reader.reset();
    146                             groovySection(reader, sw);
    147                         }
    148                         continue;
    149                     }
    150                 }
    151                 if (c == '\"') {
    152                     sw.write('//');
    153                 }
    154                 sw.write(c);
    155             }
    156             endScript(sw);
    157             String result = sw.toString();
    158             //System.out.println( "source text:\n" + result );
    159             return result;
    160         }
    161
    162         private void startScript(StringWriter sw) {
    163             sw.write("/* Generated by SimpleTemplateEngine */ ");
    164             sw.write("out.print(\"");
    165         }
    166
    167         private void endScript(StringWriter sw) {
    168             sw.write("\");\n");
    169         }
    170
    171         /***
    172          * Closes the currently open write and writes out the following text as a GString expression until it reaches an end %>.
    173          *
    174          * @param reader
    175          * @param sw
    176          * @throws IOException
    177          */
    178         private void groovyExpression(Reader reader, StringWriter sw) throws IOException {
    179             sw.write("\");out.print(\"${");
    180             int c;
    181             while((c = reader.read()) != -1) {
    182                 if (c == '%') {
    183                     c = reader.read();
    184                     if (c != '>') {
    185                         sw.write('%');
    186                     } else {
    187                         break;
    188                     }
    189                 }
    190                 sw.write(c);
    191             }
    192             sw.write("}\");out.print(\"");
    193         }
    194
    195         /***
    196          * Closes the currently open write and writes the following text as normal Groovy script code until it reaches an end %>.
    197          *
    198          * @param reader
    199          * @param sw
    200          * @throws IOException
    201          */
    202         private void groovySection(Reader reader, StringWriter sw) throws IOException {
    203             sw.write("\");");
    204             int c;
    205             while((c = reader.read()) != -1) {
    206                 if (c == '%') {
    207                     c = reader.read();
    208                     if (c != '>') {
    209                         sw.write('%');
    210                     } else {
    211                         break;
    212                     }
    213                 }
    214                 sw.write(c);
    215             }
    216             sw.write(";out.print(\"");
    217         }
    218
    219     }
    220 }