View Javadoc

1   /*
2    * $Id: SimpleTemplateEngine.java,v 1.12 2004/05/12 20:29:04 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                     c = reader.read();
134                     if (c != '%') {
135                         sw.write('<');
136                     } else {
137                         reader.mark(1);
138                         c = reader.read();
139                         if (c == '=') {
140                             groovyExpression(reader, sw);
141                         } else {
142                             reader.reset();
143                             groovySection(reader, sw);
144                         }
145                         continue;
146                     }
147                 }
148                 if (c == '\"') {
149                     sw.write('//');
150                 }
151                 sw.write(c);
152             }
153             endScript(sw);
154             String result = sw.toString();
155             //System.out.println( "source text:\n" + result );
156             return result;
157         }
158 
159         private void startScript(StringWriter sw) {
160             sw.write("/* Generated by SimpleTemplateEngine */ ");
161             sw.write("out.print(\"");
162         }
163 
164         private void endScript(StringWriter sw) {
165             sw.write("\");\n");
166         }
167 
168         /***
169          * Closes the currently open write and writes out the following text as a GString expression until it reaches an end %>.
170          * 
171          * @param reader
172          * @param sw
173          * @throws IOException
174          */
175         private void groovyExpression(Reader reader, StringWriter sw) throws IOException {
176             sw.write("\");out.print(\"${");
177             int c;
178             while((c = reader.read()) != -1) {
179                 if (c == '%') {
180                     c = reader.read();
181                     if (c != '>') {
182                         sw.write('%');
183                     } else {
184                         break;
185                     }
186                 }
187                 sw.write(c);
188             }
189             sw.write("}\");out.print(\"");
190         }
191 
192         /***
193          * Closes the currently open write and writes the following text as normal Groovy script code until it reaches an end %>.
194          * 
195          * @param reader
196          * @param sw
197          * @throws IOException
198          */
199         private void groovySection(Reader reader, StringWriter sw) throws IOException {
200             sw.write("\");");
201             int c;
202             while((c = reader.read()) != -1) {
203                 if (c == '%') {
204                     c = reader.read();
205                     if (c != '>') {
206                         sw.write('%');
207                     } else {
208                         break;
209                     }
210                 }
211                 sw.write(c);
212             }
213             sw.write(";out.print(\"");
214         }
215 
216     }
217 }