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> 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 }