1.1 restoration
[mir.git] / source / mir / generator / tal / template / CoreTemplateNodeLibrary.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 \r
31 package mir.generator.tal.template;\r
32 \r
33 import java.util.*;\r
34 \r
35 import mir.generator.tal.interfaces.TALExpressionParser;\r
36 import mir.generator.tal.interfaces.TALLogger;\r
37 import mir.util.HTMLRoutines;\r
38 import mir.util.StringRoutines;\r
39 import mir.util.xml.XMLName;\r
40 import mir.util.xml.XMLParserExc;\r
41 import mir.util.xml.XMLReaderTool;\r
42 \r
43 public class CoreTemplateNodeLibrary implements TemplateNodeLibrary {\r
44   private String prefix;\r
45   private String uri;\r
46 \r
47   private boolean isOurTag(XMLName aName) {\r
48     return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());\r
49   }\r
50 \r
51   public CoreTemplateNodeLibrary(String aPrefix, String aUri) {\r
52     prefix = aPrefix;\r
53     uri = aUri;\r
54   }\r
55 \r
56   private static final String CONDITION_ATTRIBUTE = "condition";\r
57   private static final String REPEAT_ATTRIBUTE = "repeat";\r
58   private static final String CONTENT_ATTRIBUTE = "content";\r
59   private static final String ERROR_ATTRIBUTE = "on-error";\r
60   private static final String REPLACE_ATTRIBUTE = "replace";\r
61   private static final String DEFINITION_ATTRIBUTE = "define";\r
62   private static final String OMITTAG_ATTRIBUTE = "omit-tag";\r
63   private static final String ATTRIBUTE_ATTRIBUTE = "attributes";\r
64 \r
65   public TemplateNode constructTemplateNode(TALExpressionParser aParser, XMLName aTag, Map anAttributes,\r
66       TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {\r
67     TALBasicTemplateNode result = new TALBasicTemplateNode(XMLReaderTool.normalizeXMLName(aTag));\r
68     result.setBody(aChildTemplateNode);\r
69 \r
70     if (isOurTag(aTag))\r
71       result.setOmitTag(aParser.preparseTRUE());\r
72 \r
73     Iterator i = anAttributes.entrySet().iterator();\r
74     while (i.hasNext()) {\r
75       Map.Entry entry = (Map.Entry) i.next();\r
76       XMLName name = (XMLName) entry.getKey();\r
77 \r
78       if (!isOurTag(name)) {\r
79         result.addFixedAttribute(XMLReaderTool.normalizeXMLName(name), (String) entry.getValue());\r
80       }\r
81       else {\r
82         if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {\r
83           List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
84 \r
85           Iterator j = definitions.iterator();\r
86           while (j.hasNext())\r
87           {\r
88             List parts = StringRoutines.separateString((String) j.next(), " ");\r
89 \r
90             if (parts.size()==2) {\r
91               result.addDefinition(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
92             }\r
93           }\r
94         }\r
95         else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {\r
96           result.setCondition(aParser.preparseBooleanExpression((String) entry.getValue()));\r
97         }\r
98         else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {\r
99           result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
100         }\r
101         else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {\r
102           result.setError(aParser.preparseStringExpression((String) entry.getValue()));\r
103         }\r
104         else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {\r
105           if (((String) entry.getValue()).trim().length()==0)\r
106             result.setOmitTag(aParser.preparseTRUE());\r
107           else\r
108             result.setOmitTag(aParser.preparseBooleanExpression((String) entry.getValue()));\r
109         }\r
110         else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {\r
111           result.setOmitTag(aParser.preparseTRUE());\r
112           result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
113         }\r
114         else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {\r
115           List parts = StringRoutines.separateString((String) entry.getValue(), " ");\r
116 \r
117           if (parts.size()==2) {\r
118             result.setRepeat(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
119           }\r
120         }\r
121         else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {\r
122           List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
123 \r
124           Iterator j = attributes.iterator();\r
125           while (j.hasNext()) {\r
126             String value = (String) j.next();\r
127             List parts = StringRoutines.separateString(value.trim(), " ");\r
128 \r
129             if (parts.size()==2) {\r
130               result.addModifiedAttribute((String) parts.get(0), aParser.preparseExpression((String) parts.get(1)));\r
131             }\r
132             else {\r
133               throw new XMLParserExc(ATTRIBUTE_ATTRIBUTE + " tag should have exactly 2 parts ("+value+")");\r
134             }\r
135           }\r
136         }\r
137       }\r
138     }\r
139 \r
140     return result;\r
141   }\r
142 \r
143   public static class TALBasicTemplateNode implements TemplateNode {\r
144     private String tag;\r
145     private Map fixedAttributes;\r
146     private Map attributeModifiers;\r
147 \r
148     private List definitions;\r
149     private Object condition;\r
150 \r
151     private Object repeatVariable;\r
152     private Object repeatExpression;\r
153     private Object contentExpression;\r
154     private Object omitTagExpression;\r
155     private Object errorExpression;\r
156 \r
157     private TemplateNode body;\r
158 \r
159     public TALBasicTemplateNode(String aTag) {\r
160       tag = aTag;\r
161 \r
162       fixedAttributes = new HashMap();\r
163       attributeModifiers = new HashMap();\r
164 \r
165       definitions = new ArrayList();\r
166       condition = null;\r
167 \r
168       repeatVariable = null;\r
169       repeatExpression = null;\r
170       contentExpression = null;\r
171       omitTagExpression = null;\r
172 \r
173       body = null;\r
174     }\r
175 \r
176     public void setBody(TemplateNode aBody) {\r
177       body = aBody;\r
178     }\r
179 \r
180     public void addFixedAttribute(String aKey, String aValue) {\r
181       fixedAttributes.put(aKey, aValue);\r
182     }\r
183 \r
184     public void addModifiedAttribute(String aKey, Object aValue) {\r
185       attributeModifiers.put(aKey, aValue);\r
186     }\r
187 \r
188     public void addDefinition(Object aKey, Object aValue) {\r
189       definitions.add(new Definition(aKey, aValue));\r
190     }\r
191 \r
192     public void setCondition(Object aCondition) {\r
193       condition = aCondition;\r
194     }\r
195 \r
196     public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
197       repeatVariable = aRepeatVariable;\r
198       repeatExpression = aRepeatExpression;\r
199     }\r
200 \r
201     public void setContent(Object aContentExpression) {\r
202       contentExpression = aContentExpression;\r
203     }\r
204 \r
205     public void setOmitTag(Object anOmitTagExpression) {\r
206       omitTagExpression = anOmitTagExpression;\r
207     }\r
208 \r
209     public void setError(Object anErrorExpression) {\r
210       errorExpression = anErrorExpression;\r
211     }\r
212 \r
213     public static class Definition {\r
214       private Object variable;\r
215       private Object expression;\r
216 \r
217       public Definition(Object aVariable, Object anExpression) {\r
218         variable = aVariable;\r
219         expression = anExpression;\r
220       }\r
221 \r
222       public Object getVariable() {\r
223         return variable;\r
224       }\r
225 \r
226       public Object getExpression() {\r
227         return expression;\r
228       }\r
229     }\r
230 \r
231     public void process(TALExpressionParser aParser, Object aContext,\r
232         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
233         TemplateLibrary aLibrary) throws TemplateProcessingException {\r
234       if (errorExpression != null) {\r
235         StringBuffer destination = new StringBuffer();\r
236 \r
237         try {\r
238           outerProcess(aParser, aContext, destination, aLogger, aTemplateContext, aLibrary);\r
239         }\r
240         catch (Throwable t) {\r
241           try {\r
242 //            destination.delete(0, destination.length());\r
243             aParser.processPseudoAssignment(aContext, "exception", t);\r
244             destination.insert(0, aParser.evaluateStringExpression(aContext, errorExpression));\r
245             destination.append(" >>>ERROR POSITION<<< ");\r
246           }\r
247           catch (Throwable s) {\r
248             throw new TemplateProcessingException(s);\r
249           }\r
250         }\r
251         finally {\r
252           aDestination.append(destination);\r
253         }\r
254       }\r
255       else {\r
256         outerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
257       }\r
258     }\r
259 \r
260     public String getPlainText() {\r
261       return body.getPlainText();\r
262     }\r
263 \r
264     public void outerProcess(TALExpressionParser aParser, Object aContext,\r
265         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
266         TemplateLibrary aLibrary) throws TemplateProcessingException {\r
267 \r
268       Object oldAttributes = aParser.evaluatePseudoVariable(aContext, "tagattributes");\r
269       aParser.processPseudoAssignment(aContext, "tagattributes", Collections.unmodifiableMap(fixedAttributes));\r
270 \r
271       Object oldContent = aParser.evaluatePseudoVariable(aContext, "tagcontent");\r
272       aParser.processPseudoAssignment(aContext, "tagcontent", body.getPlainText());\r
273 \r
274       try {\r
275         Iterator i;\r
276 \r
277         i = definitions.iterator();\r
278         while (i.hasNext()) {\r
279           Definition d = (Definition) i.next();\r
280           aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
281         }\r
282 \r
283         if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
284           if (repeatExpression != null) {\r
285             i = aParser.evaluateListExpression(aContext, repeatExpression);\r
286 \r
287             while (i.hasNext()) {\r
288               aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
289               innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
290             }\r
291           }\r
292           else {\r
293             innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
294           }\r
295         }\r
296       }\r
297       finally {\r
298         try {\r
299           aParser.processPseudoAssignment(aContext, "tagattributes", oldAttributes);\r
300           aParser.processPseudoAssignment(aContext, "tagcontent", oldContent);\r
301         }\r
302         catch (Throwable t) {\r
303         }\r
304       }\r
305     };\r
306 \r
307     private void innerProcess(TALExpressionParser aParser, Object aContext,\r
308         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary)\r
309         throws TemplateProcessingException {\r
310 \r
311       boolean omitTag = false;\r
312       StringBuffer content = aDestination;\r
313 \r
314       if (omitTagExpression != null)\r
315         omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
316 \r
317       if (!omitTag) {\r
318         content = new StringBuffer();\r
319         Map generatedAttributes = new HashMap(fixedAttributes);\r
320 \r
321         Iterator i = attributeModifiers.entrySet().iterator();\r
322         while (i.hasNext()) {\r
323           Map.Entry entry = (Map.Entry) i.next();\r
324 \r
325           generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
326         }\r
327 \r
328         aDestination.append("<");\r
329         aDestination.append(tag);\r
330 \r
331         i = generatedAttributes.entrySet().iterator();\r
332         while (i.hasNext()) {\r
333           Map.Entry entry = (Map.Entry) i.next();\r
334           aDestination.append(" ");\r
335           aDestination.append(entry.getKey());\r
336           aDestination.append("=");\r
337           aDestination.append("\"");\r
338           aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
339           aDestination.append("\"");\r
340         }\r
341       }\r
342 \r
343       try{\r
344         if (contentExpression != null) {\r
345           content.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
346         }\r
347         else {\r
348           if (body != null) {\r
349             body.process(aParser, aContext, content, aLogger, aTemplateContext, aLibrary);\r
350           }\r
351         }\r
352         if (!omitTag) {\r
353           if (content.length()==0) {\r
354             aDestination.append(" />");\r
355           }\r
356           else {\r
357             aDestination.append(">");\r
358             aDestination.append(content);\r
359             aDestination.append("</");\r
360             aDestination.append(tag);\r
361             aDestination.append(">");\r
362           }\r
363         }\r
364       }\r
365       catch (Throwable t) {\r
366         if (!omitTag) {\r
367           aDestination.append(content);\r
368         }\r
369 \r
370         if (t instanceof TemplateProcessingException) {\r
371           throw (TemplateProcessingException) t;\r
372         }\r
373         else if (t instanceof RuntimeException) {\r
374           throw (RuntimeException) t;\r
375         }\r
376         else throw new TemplateProcessingException(t.toString());\r
377       }\r
378     }\r
379   }\r
380 }\r