1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package 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
62
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
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 }