Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/xpn/xwiki/render/groovy/GroovyTemplateEngine.java


1   /**
2    * ===================================================================
3    *
4    * Copyright (c) 2003,2004 Ludovic Dubost, All rights reserved.
5    *
6    * This program is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public License
8    * as published by the Free Software Foundation; either version 2
9    * of the License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Lesser General Public License for more details, published at 
15   * http://www.gnu.org/copyleft/lesser.html or in lesser.txt in the
16   * root folder of this distribution.
17  
18   * Created by
19   * User: Ludovic Dubost
20   * Date: 19 sept. 2004
21   * Time: 21:10:40
22   */
23  package com.xpn.xwiki.render.groovy;
24  
25  import groovy.text.*;
26  import groovy.lang.GroovyShell;
27  import groovy.lang.Script;
28  import groovy.lang.Binding;
29  import groovy.lang.Writable;
30  
31  import java.io.*;
32  import java.util.Map;
33  
34  import org.codehaus.groovy.control.CompilationFailedException;
35  import org.codehaus.groovy.runtime.InvokerHelper;
36  
37  /*
38   * $Id: GroovyTemplateEngine.java 444 2005-01-20 00:06:15Z ldubost $version Mar 8, 2004 2:11:00 AM $user Exp $
39   *
40   * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
41   *
42   * Redistribution and use of this software and associated documentation
43   * ("Software"), with or without modification, are permitted provided that the
44   * following conditions are met: 1. Redistributions of source code must retain
45   * copyright statements and notices. Redistributions must also contain a copy
46   * of this document. 2. Redistributions in binary form must reproduce the above
47   * copyright notice, this list of conditions and the following disclaimer in
48   * the documentation and/or other materials provided with the distribution. 3.
49   * The name "groovy" must not be used to endorse or promote products derived
50   * from this Software without prior written permission of The Codehaus. For
51   * written permission, please contact info@codehaus.org. 4. Products derived
52   * from this Software may not be called "groovy" nor may "groovy" appear in
53   * their names without prior written permission of The Codehaus. "groovy" is a
54   * registered trademark of The Codehaus. 5. Due credit should be given to The
55   * Codehaus - http://groovy.codehaus.org/
56   *
57   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
58   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
59   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
60   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
61   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
63   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
64   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
67   * DAMAGE.
68   *
69   */
70  
71  
72     /**
73  * This simple template engine uses JSP <% %> script and <%= %> expression syntax.  It also lets you use normal groovy expressions in
74  * 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.
75  *
76  * @author sam
77  */
78     public class GroovyTemplateEngine extends TemplateEngine {
79  
80     /* (non-Javadoc)
81      * @see groovy.util.TemplateEngine#createTemplate(java.io.Reader)
82      */
83     public Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
84         com.xpn.xwiki.render.groovy.GroovyTemplateEngine.SimpleTemplate template = new com.xpn.xwiki.render.groovy.GroovyTemplateEngine.SimpleTemplate();
85         GroovyShell shell = new GroovyShell();
86         String script = template.parse(reader);
87         template.script = shell.parse(script);
88         return template;
89     }
90  
91     private static class SimpleTemplate implements Template {
92  
93         private Script script;
94         private Binding binding;
95         private Map map;
96  
97         /**
98          * Set the binding for the template.  Keys will be converted to Strings.
99          *
100         * @see groovy.text.Template#setBinding(java.util.Map)
101         */
102        public void setBinding(final Map map) {
103            this.map = map;
104            binding = new Binding(map);
105        }
106 
107        /**
108         * Write the template document with the set binding applied to the writer.
109         *
110         * @see groovy.lang.Writable#writeTo(java.io.Writer)
111         */
112        public Writer writeTo(Writer writer) throws IOException {
113            if (binding == null) binding = new Binding();
114            Script scriptObject = InvokerHelper.createScript(script.getClass(), binding);
115            PrintWriter pw = new PrintWriter(writer);
116            scriptObject.setProperty("out", pw);
117            scriptObject.run();
118            pw.flush();
119            return writer;
120        }
121 
122        /**
123         * Convert the template and binding into a result String.
124         *
125         * @see java.lang.Object#toString()
126         */
127        public String toString() {
128            try {
129                StringWriter sw = new StringWriter();
130                writeTo(sw);
131                return sw.toString();
132            } catch (Exception e) {
133                return e.toString();
134            }
135        }
136 
137        /**
138         * Parse the text document looking for <% or <%= and then call out to the appropriate handler, otherwise copy the text directly
139         * into the script while escaping quotes.
140         *
141         * @param reader
142         * @return
143         * @throws IOException
144         */
145        private String parse(Reader reader) throws IOException {
146            if (!reader.markSupported()) {
147                reader = new BufferedReader(reader);
148            }
149            StringWriter sw = new StringWriter();
150            startScript(sw);
151            boolean start = false;
152            int c;
153            while((c = reader.read()) != -1) {
154                if (c == '<') {
155                    c = reader.read();
156                    if (c != '%') {
157                        sw.write('<');
158                    } else {
159                        reader.mark(1);
160                        c = reader.read();
161                        if (c == '=') {
162                            groovyExpression(reader, sw);
163                        } else {
164                            reader.reset();
165                            groovySection(reader, sw);
166                        }
167                        continue;
168                    }
169                }
170                if (c == '\"') {
171                    sw.write('\\');
172                }
173                sw.write(c);
174            }
175            endScript(sw);
176            String result = sw.toString();
177            //System.out.println( "source text:\n" + result );
178            return result;
179        }
180 
181        private void startScript(StringWriter sw) {
182            sw.write("/* Generated by GroovyTemplateEngine */ ");
183            sw.write("out.print(\"");
184        }
185 
186        private void endScript(StringWriter sw) {
187            sw.write("\");\n");
188        }
189 
190        /**
191         * Closes the currently open write and writes out the following text as a GString expression until it reaches an end %>.
192         *
193         * @param reader
194         * @param sw
195         * @throws IOException
196         */
197        private void groovyExpression(Reader reader, StringWriter sw) throws IOException {
198            sw.write("\");out.print(\"${");
199            int c;
200            while((c = reader.read()) != -1) {
201                if (c == '%') {
202                    c = reader.read();
203                    if (c != '>') {
204                        sw.write('%');
205                    } else {
206                        break;
207                    }
208                }
209                sw.write(c);
210            }
211            sw.write("}\");out.print(\"");
212        }
213 
214        /**
215         * Closes the currently open write and writes the following text as normal Groovy script code until it reaches an end %>.
216         *
217         * @param reader
218         * @param sw
219         * @throws IOException
220         */
221        private void groovySection(Reader reader, StringWriter sw) throws IOException {
222            sw.write("\");");
223            int c;
224            while((c = reader.read()) != -1) {
225                if (c == '%') {
226                    c = reader.read();
227                    if (c != '>') {
228                        sw.write('%');
229                    } else {
230                        break;
231                    }
232                }
233                sw.write(c);
234            }
235            sw.write(";out.print(\"");
236        }
237 
238        public Writable make() {
239            return make(null);
240        }
241 
242        public Writable make(final Map map) {
243            return new Writable() {
244                /**
245                 * Write the template document with the set binding applied to the writer.
246                 *
247                 * @see groovy.lang.Writable#writeTo(java.io.Writer)
248                 */
249                public Writer writeTo(Writer writer) throws IOException {
250                    Binding binding;
251                    if (map == null) binding = new Binding(); else binding = new Binding(map);
252                    Script scriptObject = InvokerHelper.createScript(script.getClass(), binding);
253                    PrintWriter pw = new PrintWriter(writer);
254                    scriptObject.setProperty("out", pw);
255                    scriptObject.run();
256                    pw.flush();
257                    return writer;
258                }
259 
260                /**
261                 * Convert the template and binding into a result String.
262                 *
263                 * @see java.lang.Object#toString()
264                 */
265                public String toString() {
266                    try {
267                        StringWriter sw = new StringWriter();
268                        writeTo(sw);
269                        return sw.toString();
270                    } catch (Exception e) {
271                        return e.toString();
272                    }
273                }
274            };
275        }
276    }
277    }