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