cleanup / abuse system fix / prepping for a release
[mir.git] / source / mir / generator / tal / template / CoreTemplateNodeLibrary.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30
31 package mir.generator.tal.template;
32
33 import java.util.*;
34
35 import mir.generator.tal.interfaces.TALExpressionParser;
36 import mir.generator.tal.interfaces.TALLogger;
37 import mir.util.HTMLRoutines;
38 import mir.util.StringRoutines;
39 import mir.util.xml.XMLName;
40 import mir.util.xml.XMLParserExc;
41 import mir.util.xml.XMLReaderTool;
42
43 public class CoreTemplateNodeLibrary implements TemplateNodeLibrary {
44   private String prefix;
45   private String uri;
46
47   private boolean isOurTag(XMLName aName) {
48     return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());
49   }
50
51   public CoreTemplateNodeLibrary(String aPrefix, String aUri) {
52     prefix = aPrefix;
53     uri = aUri;
54   }
55
56   private static final String CONDITION_ATTRIBUTE = "condition";
57   private static final String REPEAT_ATTRIBUTE = "repeat";
58   private static final String CONTENT_ATTRIBUTE = "content";
59   private static final String ERROR_ATTRIBUTE = "on-error";
60   private static final String REPLACE_ATTRIBUTE = "replace";
61   private static final String DEFINITION_ATTRIBUTE = "define";
62   private static final String OMITTAG_ATTRIBUTE = "omit-tag";
63   private static final String ATTRIBUTE_ATTRIBUTE = "attributes";
64
65   public TemplateNode constructTemplateNode(TALExpressionParser aParser, XMLName aTag, Map anAttributes,
66       TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {
67     TALBasicTemplateNode result = new TALBasicTemplateNode(XMLReaderTool.normalizeXMLName(aTag));
68     result.setBody(aChildTemplateNode);
69
70     if (isOurTag(aTag))
71       result.setOmitTag(aParser.preparseTRUE());
72
73     Iterator i = anAttributes.entrySet().iterator();
74     while (i.hasNext()) {
75       Map.Entry entry = (Map.Entry) i.next();
76       XMLName name = (XMLName) entry.getKey();
77
78       if (!isOurTag(name)) {
79         result.addFixedAttribute(XMLReaderTool.normalizeXMLName(name), (String) entry.getValue());
80       }
81       else {
82         if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {
83           List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');
84
85           Iterator j = definitions.iterator();
86           while (j.hasNext())
87           {
88             List parts = StringRoutines.separateString((String) j.next(), " ");
89
90             if (parts.size()==2) {
91               result.addDefinition(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));
92             }
93           }
94         }
95         else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {
96           result.setCondition(aParser.preparseBooleanExpression((String) entry.getValue()));
97         }
98         else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {
99           result.setContent(aParser.preparseStringExpression((String) entry.getValue()));
100         }
101         else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {
102           result.setError(aParser.preparseStringExpression((String) entry.getValue()));
103         }
104         else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {
105           if (((String) entry.getValue()).trim().length()==0)
106             result.setOmitTag(aParser.preparseTRUE());
107           else
108             result.setOmitTag(aParser.preparseBooleanExpression((String) entry.getValue()));
109         }
110         else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {
111           result.setOmitTag(aParser.preparseTRUE());
112           result.setContent(aParser.preparseStringExpression((String) entry.getValue()));
113         }
114         else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {
115           List parts = StringRoutines.separateString((String) entry.getValue(), " ");
116
117           if (parts.size()==2) {
118             result.setRepeat(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));
119           }
120         }
121         else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {
122           List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');
123
124           Iterator j = attributes.iterator();
125           while (j.hasNext()) {
126             String value = (String) j.next();
127             List parts = StringRoutines.separateString(value.trim(), " ");
128
129             if (parts.size()==2) {
130               result.addModifiedAttribute((String) parts.get(0), aParser.preparseExpression((String) parts.get(1)));
131             }
132             else {
133               throw new XMLParserExc(ATTRIBUTE_ATTRIBUTE + " tag should have exactly 2 parts ("+value+")");
134             }
135           }
136         }
137       }
138     }
139
140     return result;
141   }
142
143   public static class TALBasicTemplateNode implements TemplateNode {
144     private String tag;
145     private Map fixedAttributes;
146     private Map attributeModifiers;
147
148     private List definitions;
149     private Object condition;
150
151     private Object repeatVariable;
152     private Object repeatExpression;
153     private Object contentExpression;
154     private Object omitTagExpression;
155     private Object errorExpression;
156
157     private TemplateNode body;
158
159     public TALBasicTemplateNode(String aTag) {
160       tag = aTag;
161
162       fixedAttributes = new HashMap();
163       attributeModifiers = new HashMap();
164
165       definitions = new ArrayList();
166       condition = null;
167
168       repeatVariable = null;
169       repeatExpression = null;
170       contentExpression = null;
171       omitTagExpression = null;
172
173       body = null;
174     }
175
176     public void setBody(TemplateNode aBody) {
177       body = aBody;
178     }
179
180     public void addFixedAttribute(String aKey, String aValue) {
181       fixedAttributes.put(aKey, aValue);
182     }
183
184     public void addModifiedAttribute(String aKey, Object aValue) {
185       attributeModifiers.put(aKey, aValue);
186     }
187
188     public void addDefinition(Object aKey, Object aValue) {
189       definitions.add(new Definition(aKey, aValue));
190     }
191
192     public void setCondition(Object aCondition) {
193       condition = aCondition;
194     }
195
196     public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {
197       repeatVariable = aRepeatVariable;
198       repeatExpression = aRepeatExpression;
199     }
200
201     public void setContent(Object aContentExpression) {
202       contentExpression = aContentExpression;
203     }
204
205     public void setOmitTag(Object anOmitTagExpression) {
206       omitTagExpression = anOmitTagExpression;
207     }
208
209     public void setError(Object anErrorExpression) {
210       errorExpression = anErrorExpression;
211     }
212
213     public static class Definition {
214       private Object variable;
215       private Object expression;
216
217       public Definition(Object aVariable, Object anExpression) {
218         variable = aVariable;
219         expression = anExpression;
220       }
221
222       public Object getVariable() {
223         return variable;
224       }
225
226       public Object getExpression() {
227         return expression;
228       }
229     }
230
231     public void process(TALExpressionParser aParser, Object aContext,
232         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,
233         TemplateLibrary aLibrary) throws TemplateProcessingException {
234       if (errorExpression != null) {
235         StringBuffer destination = new StringBuffer();
236
237         try {
238           outerProcess(aParser, aContext, destination, aLogger, aTemplateContext, aLibrary);
239         }
240         catch (Throwable t) {
241           try {
242 //            destination.delete(0, destination.length());
243             aParser.processPseudoAssignment(aContext, "exception", t);
244             destination.insert(0, aParser.evaluateStringExpression(aContext, errorExpression));
245             destination.append(" >>>ERROR POSITION<<< ");
246           }
247           catch (Throwable s) {
248             throw new TemplateProcessingException(s);
249           }
250         }
251         finally {
252           aDestination.append(destination);
253         }
254       }
255       else {
256         outerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
257       }
258     }
259
260     public String getPlainText() {
261       return body.getPlainText();
262     }
263
264     public void outerProcess(TALExpressionParser aParser, Object aContext,
265         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,
266         TemplateLibrary aLibrary) throws TemplateProcessingException {
267
268       Object oldAttributes = aParser.evaluatePseudoVariable(aContext, "tagattributes");
269       aParser.processPseudoAssignment(aContext, "tagattributes", Collections.unmodifiableMap(fixedAttributes));
270
271       Object oldContent = aParser.evaluatePseudoVariable(aContext, "tagcontent");
272       aParser.processPseudoAssignment(aContext, "tagcontent", body.getPlainText());
273
274       try {
275         Iterator i;
276
277         i = definitions.iterator();
278         while (i.hasNext()) {
279           Definition d = (Definition) i.next();
280           aParser.processAssignment(aContext, d.getVariable(), d.getExpression());
281         }
282
283         if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {
284           if (repeatExpression != null) {
285             i = aParser.evaluateListExpression(aContext, repeatExpression);
286
287             while (i.hasNext()) {
288               aParser.processDirectAssignment(aContext, repeatVariable, i.next());
289               innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
290             }
291           }
292           else {
293             innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
294           }
295         }
296       }
297       finally {
298         try {
299           aParser.processPseudoAssignment(aContext, "tagattributes", oldAttributes);
300           aParser.processPseudoAssignment(aContext, "tagcontent", oldContent);
301         }
302         catch (Throwable t) {
303         }
304       }
305     }
306
307     private void innerProcess(TALExpressionParser aParser, Object aContext,
308         StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary)
309         throws TemplateProcessingException {
310
311       boolean omitTag = false;
312       StringBuffer content = aDestination;
313
314       if (omitTagExpression != null)
315         omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);
316
317       if (!omitTag) {
318         content = new StringBuffer();
319         Map generatedAttributes = new TreeMap(fixedAttributes);
320
321         Iterator i = attributeModifiers.entrySet().iterator();
322         while (i.hasNext()) {
323           Map.Entry entry = (Map.Entry) i.next();
324
325           generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));
326         }
327
328         aDestination.append("<");
329         aDestination.append(tag);
330
331         i = generatedAttributes.entrySet().iterator();
332         while (i.hasNext()) {
333           Map.Entry entry = (Map.Entry) i.next();
334           aDestination.append(" ");
335           aDestination.append(entry.getKey());
336           aDestination.append("=");
337           aDestination.append("\"");
338           aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));
339           aDestination.append("\"");
340         }
341       }
342
343       try{
344         if (contentExpression != null) {
345           content.append(aParser.evaluateStringExpression(aContext, contentExpression));
346         }
347         else {
348           if (body != null) {
349             body.process(aParser, aContext, content, aLogger, aTemplateContext, aLibrary);
350           }
351         }
352         if (!omitTag) {
353           if (content.length()==0) {
354             aDestination.append(" />");
355           }
356           else {
357             aDestination.append(">");
358             aDestination.append(content);
359             aDestination.append("</");
360             aDestination.append(tag);
361             aDestination.append(">");
362           }
363         }
364       }
365       catch (Throwable t) {
366         if (!omitTag) {
367           aDestination.append(content);
368         }
369
370         if (t instanceof TemplateProcessingException) {
371           throw (TemplateProcessingException) t;
372         }
373         else if (t instanceof RuntimeException) {
374           throw (RuntimeException) t;
375         }
376         else throw new TemplateProcessingException(t.toString());
377       }
378     }
379   }
380 }