file i/o buffering
[mir.git] / source / mir / generator / tal / TALTemplate.java
1 /*\r
2  * Copyright (C) 2001, 2002 The Mir-coders group\r
3  *\r
4  * This file is part of Mir.\r
5  *\r
6  * Mir is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 2 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Mir is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with Mir; if not, write to the Free Software\r
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19  *\r
20  * In addition, as a special exception, The Mir-coders gives permission to link\r
21  * the code of this program with  any library licensed under the Apache Software License,\r
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
23  * (or with modified versions of the above that use the same license as the above),\r
24  * and distribute linked combinations including the two.  You must obey the\r
25  * GNU General Public License in all respects for all of the code used other than\r
26  * the above mentioned libraries.  If you modify this file, you may extend this\r
27  * exception to your version of the file, but you are not obligated to do so.\r
28  * If you do not wish to do so, delete this exception statement from your version.\r
29  */\r
30 package mir.generator.tal;\r
31 \r
32 import java.io.PrintWriter;\r
33 import java.util.HashMap;\r
34 import java.util.Iterator;\r
35 import java.util.List;\r
36 import java.util.Map;\r
37 import java.util.Vector;\r
38 \r
39 import mir.generator.tal.interfaces.TALExpressionParser;\r
40 import mir.util.HTMLRoutines;\r
41 \r
42 /**\r
43  * {@link http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4}\r
44  *\r
45  * <p>Title: </p>\r
46  * <p>Description: </p>\r
47  * <p>Copyright: Copyright (c) 2003</p>\r
48  * <p>Company: </p>\r
49  * @author not attributable\r
50  * @version 1.0\r
51  */\r
52 \r
53 public class TALTemplate {\r
54   private TemplateNode rootNode;\r
55   private TALExpressionParser parser;\r
56 \r
57   public TALTemplate(TALExpressionParser aParser, TemplateNode aRootNode) {\r
58     rootNode = aRootNode;\r
59     parser = aParser;\r
60   }\r
61 \r
62   public void processTemplate(Object aContext, PrintWriter aDestination) {\r
63     StringBuffer output = new StringBuffer();\r
64 \r
65     rootNode.process(parser, aContext, output);\r
66     aDestination.print(output);\r
67   }\r
68 \r
69   public interface TemplateNode {\r
70     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination);\r
71   }\r
72 \r
73   public static class CompositeTemplateNode\r
74       implements TemplateNode {\r
75     private List parts;\r
76 \r
77     public CompositeTemplateNode() {\r
78       parts = new Vector();\r
79     }\r
80 \r
81     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
82       Iterator i = parts.iterator();\r
83 \r
84       while (i.hasNext()) {\r
85         ((TemplateNode) i.next()).process(aParser, aContext, aDestination);\r
86       }\r
87     }\r
88 \r
89     public void appendSubNode(TemplateNode aNode) {\r
90       if (aNode instanceof CompositeTemplateNode) {\r
91         Iterator i = ((CompositeTemplateNode) aNode).parts.iterator();\r
92         while (i.hasNext()) {\r
93           appendSubNode((TemplateNode) i.next());\r
94         }\r
95       }\r
96       else if (aNode instanceof PlainTextTemplateNode && parts.size()>0 &&\r
97                (parts.get(parts.size()-1) instanceof PlainTextTemplateNode)) {\r
98 \r
99         ((PlainTextTemplateNode) parts.get(parts.size()-1)).appendText(((PlainTextTemplateNode) aNode).getText());\r
100       }\r
101       else {\r
102         parts.add(aNode);\r
103       }\r
104     }\r
105   }\r
106 \r
107   public static class PlainTextTemplateNode\r
108       implements TemplateNode {\r
109     private String text;\r
110 \r
111     public PlainTextTemplateNode() {\r
112       this("");\r
113     }\r
114 \r
115     public PlainTextTemplateNode(String aText) {\r
116       text = aText;\r
117     }\r
118 \r
119     public void appendText(String aText) {\r
120       text = text + aText;\r
121     }\r
122 \r
123     protected String getText() {\r
124       return text;\r
125     }\r
126 \r
127     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
128       aDestination.append(text);\r
129     }\r
130   }\r
131 \r
132   public static class SmartTemplateNode implements TemplateNode {\r
133     private String tag;\r
134     private Map fixedAttributes;\r
135     private Map attributeModifiers;\r
136 \r
137     private List definitions;\r
138     private Object condition;\r
139 \r
140     private Object repeatVariable;\r
141     private Object repeatExpression;\r
142     private Object contentExpression;\r
143     private Object omitTagExpression;\r
144     private Object errorExpression;\r
145 \r
146     private TemplateNode body;\r
147 \r
148     public SmartTemplateNode(String aTag) {\r
149       tag = aTag;\r
150 \r
151       fixedAttributes = new HashMap();\r
152       attributeModifiers = new HashMap();\r
153 \r
154       definitions = new Vector();\r
155       condition = null;\r
156 \r
157       repeatVariable = null;\r
158       repeatExpression = null;\r
159       contentExpression = null;\r
160       omitTagExpression = null;\r
161 \r
162       body = null;\r
163     }\r
164 \r
165     public void setBody(TemplateNode aBody) {\r
166       body = aBody;\r
167     }\r
168 \r
169     public void addFixedAttribute(String aKey, String aValue) {\r
170       fixedAttributes.put(aKey, aValue);\r
171     }\r
172 \r
173     public void addModifiedAttribute(String aKey, Object aValue) {\r
174       attributeModifiers.put(aKey, aValue);\r
175     }\r
176 \r
177     public void addDefinition(Object aKey, Object aValue) {\r
178       definitions.add(new Definition(aKey, aValue));\r
179     }\r
180 \r
181     public void setCondition(Object aCondition) {\r
182       condition = aCondition;\r
183     }\r
184 \r
185     public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
186       repeatVariable = aRepeatVariable;\r
187       repeatExpression = aRepeatExpression;\r
188     }\r
189 \r
190     public void setContent(Object aContentExpression) {\r
191       contentExpression = aContentExpression;\r
192     }\r
193 \r
194     public void setOmitTag(Object anOmitTagExpression) {\r
195       omitTagExpression = anOmitTagExpression;\r
196     }\r
197 \r
198     public void setError(Object anErrorExpression) {\r
199       errorExpression = anErrorExpression;\r
200     }\r
201 \r
202     public static class Definition {\r
203       private Object variable;\r
204       private Object expression;\r
205 \r
206       public Definition(Object aVariable, Object anExpression) {\r
207         variable = aVariable;\r
208         expression = anExpression;\r
209       }\r
210 \r
211       public Object getVariable() {\r
212         return variable;\r
213       }\r
214 \r
215       public Object getExpression() {\r
216         return expression;\r
217       }\r
218     }\r
219 \r
220     public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
221       Iterator i;\r
222 \r
223         i = definitions.iterator();\r
224         while (i.hasNext()) {\r
225           Definition d = (Definition) i.next();\r
226           aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
227         }\r
228 \r
229         if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
230           if (repeatExpression != null) {\r
231             i = aParser.evaluateListExpression(aContext, repeatExpression);\r
232 \r
233             while (i.hasNext()) {\r
234               aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
235               innerProcess(aParser, aContext, aDestination);\r
236             }\r
237           }\r
238           else {\r
239             innerProcess(aParser, aContext, aDestination);\r
240           }\r
241         }\r
242     };\r
243 \r
244     private void innerProcess(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
245       boolean omitTag = false;\r
246       if (omitTagExpression != null)\r
247         omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
248 \r
249       if (!omitTag) {\r
250         Map generatedAttributes = new HashMap(fixedAttributes);\r
251 \r
252         Iterator i = attributeModifiers.keySet().iterator();\r
253         while (i.hasNext()) {\r
254           Map.Entry entry = (Map.Entry) i.next();\r
255 \r
256           generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
257         }\r
258 \r
259         aDestination.append("<");\r
260         aDestination.append(tag);\r
261 \r
262         i = generatedAttributes.entrySet().iterator();\r
263         while (i.hasNext()) {\r
264           Map.Entry entry = (Map.Entry) i.next();\r
265           aDestination.append(" ");\r
266           aDestination.append(entry.getKey());\r
267           aDestination.append("=");\r
268           aDestination.append("\"");\r
269           aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
270           aDestination.append("\"");\r
271         }\r
272         aDestination.append(">");\r
273       }\r
274 \r
275       StringBuffer destination = aDestination;\r
276       if (errorExpression != null) {\r
277         destination = new StringBuffer();\r
278       }\r
279       try {\r
280         if (contentExpression != null) {\r
281           destination.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
282         }\r
283         else {\r
284           if (body != null)\r
285             body.process(aParser, aContext, destination);\r
286         }\r
287       }\r
288       catch (RuntimeException t) {\r
289         if (errorExpression != null) {\r
290           try {\r
291             destination.delete(0, destination.length());\r
292 \r
293             aParser.processPseudoAssignment(aContext, "exception", t);\r
294             destination.append(aParser.evaluateStringExpression(aContext, errorExpression));\r
295           }\r
296           catch (Throwable s) {\r
297           }\r
298         }\r
299         else\r
300           throw t;\r
301       }\r
302       finally {\r
303         if (errorExpression != null) {\r
304           aDestination.append(destination);\r
305         }\r
306       }\r
307       if (!omitTag) {\r
308         aDestination.append("</");\r
309         aDestination.append(tag);\r
310         aDestination.append(">");\r
311       }\r
312     }\r
313   }\r
314 }