KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > projector > processor > TemplateRenderer


1 package org.apache.slide.projector.processor;
2
3 import java.io.IOException JavaDoc;
4 import java.util.ArrayList JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.List JavaDoc;
8 import java.util.Map JavaDoc;
9 import java.util.StringTokenizer JavaDoc;
10 import java.util.logging.Level JavaDoc;
11 import java.util.logging.Logger JavaDoc;
12
13 import org.apache.slide.projector.ConfigurableProcessor;
14 import org.apache.slide.projector.ConfigurationException;
15 import org.apache.slide.projector.ContentType;
16 import org.apache.slide.projector.Context;
17 import org.apache.slide.projector.ProcessException;
18 import org.apache.slide.projector.Result;
19 import org.apache.slide.projector.descriptor.AnyValueDescriptor;
20 import org.apache.slide.projector.descriptor.ParameterDescriptor;
21 import org.apache.slide.projector.descriptor.ResultDescriptor;
22 import org.apache.slide.projector.descriptor.ResultEntryDescriptor;
23 import org.apache.slide.projector.descriptor.StateDescriptor;
24 import org.apache.slide.projector.descriptor.StringValueDescriptor;
25 import org.apache.slide.projector.i18n.DefaultMessage;
26 import org.apache.slide.projector.i18n.ErrorMessage;
27 import org.apache.slide.projector.i18n.ParameterMessage;
28 import org.apache.slide.projector.util.StreamHelper;
29 import org.apache.slide.projector.value.ArrayValue;
30 import org.apache.slide.projector.value.NullValue;
31 import org.apache.slide.projector.value.PrintableValue;
32 import org.apache.slide.projector.value.StreamableValue;
33 import org.apache.slide.projector.value.StringValue;
34 import org.apache.slide.projector.value.Value;
35
36 public class TemplateRenderer implements ConfigurableProcessor {
37     private static Logger JavaDoc logger = Logger.getLogger(TemplateRenderer.class.getName());
38
39     public final static String JavaDoc OK = "ok";
40     public final static String JavaDoc OUTPUT = "output";
41     public final static String JavaDoc FRAGMENT = "fragment";
42
43     protected final static String JavaDoc FRAGMENT_START = "<!--*** Start of '";
44     protected final static String JavaDoc FRAGMENT_END = "<!--*** End of '";
45     protected final static String JavaDoc FRAGMENT_CLOSE = "' ***-->";
46
47     protected final static String JavaDoc IGNORE_START = "<!--*** Start ignore ***-->";
48     protected final static String JavaDoc IGNORE_END = "<!-- *** End ignore *** -->";
49
50     protected final static String JavaDoc TAG_OPEN = "<%";
51     protected final static String JavaDoc TAG_CLOSE = "%>";
52     protected final static String JavaDoc CONDITION_OPEN = "<?";
53     protected final static String JavaDoc CONDITION_CLOSE = "?>";
54     protected final static char SEPARATOR = ';';
55     protected final static String JavaDoc OPTIONAL = "optional";
56     protected final static String JavaDoc REQUIRED = "required";
57
58     protected final static String JavaDoc DEFAULT_FRAGMENT = "-default-fragment-";
59
60     protected final static ResultDescriptor resultDescriptor = new ResultDescriptor(
61             new StateDescriptor[] { StateDescriptor.OK_DESCRIPTOR },
62             new ResultEntryDescriptor[]{
63                 new ResultEntryDescriptor(OUTPUT, new DefaultMessage("templateRenderer/result/output"), "*", true)
64             });
65     
66     private ParameterDescriptor[] parameterDescriptors;
67
68     protected List JavaDoc parameterDescriptions;
69     protected boolean fragments;
70
71     private Map JavaDoc templates;
72     private String JavaDoc[] requiredFragments, optionalFragments;
73     private boolean ignoreUndefinedFragments = true;
74     protected List JavaDoc optionalParameters = new ArrayList JavaDoc(); // all variables used in conditions reflect optional parameters
75

76     // FIXME: Nested fragments
77
public void configure(StreamableValue config) throws ConfigurationException {
78         templates = new HashMap JavaDoc();
79         parameterDescriptions = new ArrayList JavaDoc();
80         try {
81             String JavaDoc template = StreamHelper.streamToString(config);
82             // ignore sections marked as ignored
83
int currentPosition = 0;
84             int lastPosition = 0;
85             StringBuffer JavaDoc strippedTemplate = new StringBuffer JavaDoc(template.length());
86             while ((currentPosition = template.indexOf(IGNORE_START, currentPosition)) >= 0) {
87                 strippedTemplate.append(template.substring(lastPosition, currentPosition));
88                 currentPosition = template.indexOf(IGNORE_END, currentPosition)+IGNORE_END.length();
89                 lastPosition = currentPosition;
90             }
91             strippedTemplate.append(template.substring(lastPosition));
92             template = strippedTemplate.toString();
93             
94             // split template into different fragments if fragment identifiers are found
95
currentPosition = 0;
96             boolean fragments = false;
97             while ((currentPosition = template.indexOf(FRAGMENT_START, currentPosition)) >= 0) {
98                 fragments = true;
99                 currentPosition += FRAGMENT_START.length();
100                 int startTagClose = template.indexOf(FRAGMENT_CLOSE, currentPosition);
101                 String JavaDoc fragmentName = template.substring(currentPosition, startTagClose);
102                 currentPosition = startTagClose+FRAGMENT_CLOSE.length();
103                 int fragmentEnd = template.indexOf(FRAGMENT_END, currentPosition);
104                 if ( !ignoreFragment(fragmentName) ) {
105                     Template fragment = new Template(template.substring(currentPosition, fragmentEnd));
106                     templates.put(fragmentName, fragment);
107                 }
108                 currentPosition = fragmentEnd+FRAGMENT_CLOSE.length();
109             }
110             // check if all required templates are defined
111
if (requiredFragments != null ) {
112                 for ( int i = 0; i < requiredFragments.length; i++ ) {
113                     boolean requiredFragmentDefined = false;
114                     for ( Iterator JavaDoc j = templates.keySet().iterator(); j.hasNext(); ) {
115                         String JavaDoc definedFragment = (String JavaDoc)j.next();
116                         if ( definedFragment.startsWith(requiredFragments[i]) ) {
117                             requiredFragmentDefined = true;
118                             break;
119                         }
120                     }
121                     if ( !requiredFragmentDefined ) {
122                         throw new ConfigurationException(new ErrorMessage("templateRenderer/requiredFragmentMissing", new String JavaDoc[] { requiredFragments[i] }));
123                     }
124                 }
125             }
126             parameterDescriptions.add(new ParameterDescriptor(FRAGMENT, new ParameterMessage("templateRenderer/fragment"), new StringValueDescriptor((String JavaDoc [])templates.keySet().toArray(new String JavaDoc[0])), new StringValue(DEFAULT_FRAGMENT)));
127             if ( fragments ) {
128                 if ( requiredFragments != null ) {
129                     templates.put(DEFAULT_FRAGMENT, templates.get(requiredFragments[0]));
130                 } else if ( optionalFragments != null ) {
131                     templates.put(DEFAULT_FRAGMENT, templates.get(optionalFragments[0]));
132                 }
133             } else {
134                 templates.put(DEFAULT_FRAGMENT, new Template(template));
135             }
136             parameterDescriptors = (ParameterDescriptor [])parameterDescriptions.toArray(new ParameterDescriptor[parameterDescriptions.size()]);
137         } catch (IOException JavaDoc ioexception) {
138             logger.log(Level.SEVERE, "Could not load configuration resource!");
139         }
140     }
141
142     public Result process(Map JavaDoc parameter, Context context) throws Exception JavaDoc {
143         String JavaDoc fragment = ((StringValue)parameter.get(FRAGMENT)).toString();
144         Template template = getRequiredFragment(fragment);
145         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(template.getLength());
146         template.evaluate(buffer, parameter);
147         return new Result(OK, OUTPUT, new StringValue(buffer.toString(), template.getContentType(), template.isDocument() ));
148     }
149
150     public void setRequiredFragments(String JavaDoc[] requiredFragments) {
151         this.requiredFragments = requiredFragments;
152     }
153
154     public void setOptionalFragments(String JavaDoc[] optionalFragments) {
155         this.optionalFragments = optionalFragments;
156     }
157     
158     public void ignoreUndefinedFragments(boolean ignoreUndefinedFragments) {
159         this.ignoreUndefinedFragments = ignoreUndefinedFragments;
160     }
161
162     public StringValue renderFragment(String JavaDoc fragment, Map JavaDoc parameter) throws ProcessException {
163         Template template = getRequiredFragment(fragment);
164         return renderFragment(template, parameter);
165     }
166
167     public StringValue renderFragment(Template template, Map JavaDoc parameter) throws ProcessException {
168         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(template.getLength());
169         template.evaluate(buffer, parameter);
170         return new StringValue(buffer.toString());
171     }
172
173     public void renderFragment(StringBuffer JavaDoc buffer, String JavaDoc fragment, Map JavaDoc parameter) throws ProcessException {
174         Template template = getRequiredFragment(fragment);
175         template.evaluate(buffer, parameter);
176     }
177
178     protected Template getRequiredFragment(String JavaDoc fragment) throws ProcessException {
179         Template template = (Template)templates.get(fragment);
180         if ( template == null ) throw new ProcessException(new ErrorMessage("templateArrayRenderer/fragmentNotFound", new String JavaDoc[] { fragment }));
181         return template;
182     }
183
184     protected Template getOptionalFragment(String JavaDoc fragment) {
185         return (Template)templates.get(fragment);
186     }
187
188     protected Template getOptionalFragment(String JavaDoc fragment, Template defaultTemplate) {
189         Template optionalFragment = (Template)templates.get(fragment);
190         if ( optionalFragment == null ) return defaultTemplate;
191         return optionalFragment;
192     }
193
194     public ParameterDescriptor[] getParameterDescriptors() {
195         return parameterDescriptors;
196     }
197
198     public ResultDescriptor getResultDescriptor() {
199         return resultDescriptor;
200     }
201
202     protected String JavaDoc[] getDefinedFragments() {
203         return (String JavaDoc [])templates.keySet().toArray(new String JavaDoc[templates.size()]);
204     }
205
206     protected List JavaDoc getTemplateParameterDescriptor(String JavaDoc[] fragments) {
207         List JavaDoc templateParameterDescriptors = new ArrayList JavaDoc();
208         for ( int i = 0; i < fragments.length; i++ ) {
209             Template template = (Template)templates.get(fragments[i]);
210             if ( template != null ) {
211                 templateParameterDescriptors.addAll(template.getTemplateParameterDescriptors().values());
212             }
213         }
214         return templateParameterDescriptors;
215     }
216
217     protected boolean ignoreFragment(String JavaDoc fragmentName) {
218         if ( requiredFragments == null && optionalFragments == null ) return false;
219         if ( requiredFragments != null ) {
220             for ( int i = 0; i < requiredFragments.length; i++ ) {
221                 if ( fragmentName.startsWith(requiredFragments[i])) return false;
222             }
223         }
224         if ( optionalFragments != null ) {
225             for ( int i = 0; i < optionalFragments.length; i++ ) {
226                 if ( fragmentName.startsWith(optionalFragments[i])) return false;
227             }
228         }
229         return ignoreUndefinedFragments;
230     }
231
232     protected class Template {
233         private boolean document;
234         private int length;
235         private String JavaDoc contentType;
236         private EnclosingTemplateFragment compiledTemplate = new EnclosingTemplateFragment();
237         private Map JavaDoc templateParameterDescriptors = new HashMap JavaDoc();
238
239         public Template(String JavaDoc template) {
240             length = template.length();
241             compileTemplate(template, 0, template.length(), compiledTemplate, false);
242             document = ContentType.determineIsDocument(template);
243             contentType = ContentType.determineContentType(template);
244         }
245
246         public int getLength() {
247             return length;
248         }
249
250         private int compileTemplate(String JavaDoc template, int currentPosition, int length, EnclosingTemplateFragment compiledTemplate, boolean condition) {
251             boolean tagsLeft = true;
252             do {
253                 int nextOpeningVariable = template.indexOf(TAG_OPEN, currentPosition);
254                 int nextOpeningCondition = template.indexOf(CONDITION_OPEN, currentPosition);
255                 int nextClosingCondition = template.indexOf(CONDITION_CLOSE, currentPosition);
256                 if ( nextClosingCondition != -1 && ( nextClosingCondition < nextOpeningCondition || nextOpeningCondition == -1 ) && ( nextClosingCondition < nextOpeningVariable || nextOpeningVariable == -1 ) ) {
257                     compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextClosingCondition)));
258                     currentPosition = nextClosingCondition+CONDITION_CLOSE.length();
259                     return currentPosition;
260                 } else if ( nextOpeningCondition != -1 && ( nextOpeningCondition < nextOpeningVariable || nextOpeningVariable == -1 ) ) {
261                     compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextOpeningCondition)));
262                     currentPosition = nextOpeningCondition+CONDITION_OPEN.length();
263                     String JavaDoc variable = template.substring(currentPosition, template.indexOf(' ', currentPosition));
264                     currentPosition += variable.length()+1;
265                     ConditionalTemplateFragment conditionalTemplateFragment = new ConditionalTemplateFragment(variable);
266                     compiledTemplate.addNestedTemplateFragment(conditionalTemplateFragment);
267                     currentPosition = compileTemplate(template, currentPosition, length, conditionalTemplateFragment, true);
268                 } else if ( nextOpeningVariable != -1 ) {
269                     compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition, nextOpeningVariable)));
270                     currentPosition = nextOpeningVariable+TAG_OPEN.length();
271                     int close = template.indexOf(TAG_CLOSE, currentPosition);
272                     String JavaDoc variableName = template.substring(currentPosition, close);
273                     String JavaDoc allowedContentTypes = null;
274                     boolean required = !condition;
275                     int modeSeparator = variableName.indexOf(SEPARATOR);
276                     if ( modeSeparator > 0 ) {
277                         String JavaDoc mode = variableName.substring(modeSeparator+1);
278                         variableName = variableName.substring(0, modeSeparator);
279                         int contentTypeSeparator = mode.indexOf(SEPARATOR);
280                         if ( contentTypeSeparator > 0 ) {
281                             allowedContentTypes = mode.substring(contentTypeSeparator+1);
282                             mode = mode.substring(0, contentTypeSeparator);
283                         }
284                         if ( mode.equals(OPTIONAL) ) {
285                             required = false;
286                         } else if ( mode.equals(REQUIRED) ) {
287                             required = true;
288                         } else {
289                             logger.log(Level.SEVERE, "Mode '"+mode+"' not allowed. Only optional or required are valid modes");
290                         }
291                     }
292                     AnyValueDescriptor resourceValueDescriptor = new AnyValueDescriptor();
293                     if ( !required || optionalParameters.contains(variableName)) {
294 // resourceValueDescriptor.addAllowedContentType(NullResource.CONTENT_TYPE);
295
}
296                     if ( allowedContentTypes != null ) {
297                         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(allowedContentTypes, ",");
298                         while (tokenizer.hasMoreElements()) {
299                             String JavaDoc contentTypeToken = tokenizer.nextToken();
300                             resourceValueDescriptor.addAllowedContentType(contentTypeToken);
301                         }
302                         compiledTemplate.addNestedTemplateFragment(new Variable(variableName, resourceValueDescriptor.getAllowedContentTypes(), required));
303                     } else {
304 // resourceValueDescriptor.addAllowedContentType(ContentType.ANY_TEXT);
305
compiledTemplate.addNestedTemplateFragment(new Variable(variableName, required));
306                     }
307                     ParameterDescriptor parameterDescriptor;
308                     if ( required ) {
309                         parameterDescriptor = new ParameterDescriptor(variableName, new ParameterMessage("templateVariable", new String JavaDoc[] { variableName }), resourceValueDescriptor);
310                     } else {
311                         parameterDescriptor = new ParameterDescriptor(variableName, new ParameterMessage("templateVariable", new String JavaDoc[] { variableName }), resourceValueDescriptor, new NullValue());
312                     }
313                     if ( !parameterDescriptions.contains(parameterDescriptor) ) {
314                         parameterDescriptions.add(parameterDescriptor);
315                     }
316                     templateParameterDescriptors.put(variableName, parameterDescriptor);
317                     currentPosition = close+TAG_CLOSE.length();
318                 } else {
319                     tagsLeft = false;
320                 }
321             } while ( tagsLeft );
322             compiledTemplate.addNestedTemplateFragment(new StaticTemplateFragment(template.substring(currentPosition)));
323             return currentPosition;
324         }
325
326         public Map JavaDoc getTemplateParameterDescriptors() {
327             return templateParameterDescriptors;
328         }
329
330         public boolean isDocument() {
331             return document;
332         }
333
334         public String JavaDoc getContentType() {
335             return contentType;
336         }
337
338         public void evaluate(StringBuffer JavaDoc buffer, Map JavaDoc parameter) throws ProcessException {
339             evaluate(buffer, parameter, 0);
340         }
341
342         public void evaluate(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException {
343             compiledTemplate.render(buffer, parameter, index);
344         }
345     }
346
347     interface TemplateFragment {
348         public void render(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException;
349     }
350
351     class StaticTemplateFragment implements TemplateFragment {
352         private String JavaDoc content;
353
354         public StaticTemplateFragment(String JavaDoc content) {
355             this.content = content;
356         }
357
358         public void render(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException {
359             buffer.append(content);
360         }
361     }
362
363     class EnclosingTemplateFragment implements TemplateFragment {
364         private List JavaDoc nestedTemplateFragments = new ArrayList JavaDoc();
365
366         public void render(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException {
367             for ( Iterator JavaDoc i = nestedTemplateFragments.iterator(); i.hasNext(); ) {
368                 TemplateFragment fragment = (TemplateFragment)i.next();
369                 fragment.render(buffer, parameter, index);
370             }
371         }
372
373         public void addNestedTemplateFragment(Object JavaDoc fragment) {
374             nestedTemplateFragments.add(fragment);
375         }
376     }
377
378     class ConditionalTemplateFragment extends EnclosingTemplateFragment {
379         private String JavaDoc variable;
380
381         public ConditionalTemplateFragment(String JavaDoc variable) {
382             this.variable = variable;
383             optionalParameters.add(variable);
384             if ( parameterDescriptions.contains(variable) ) {
385                 ((AnyValueDescriptor)((ParameterDescriptor)parameterDescriptions.get(parameterDescriptions.indexOf(variable))).getValueDescriptor()).addAllowedContentType(NullValue.CONTENT_TYPE);
386             }
387         }
388
389         public String JavaDoc getVariable() {
390             return variable;
391         }
392
393         public void render(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException {
394             Object JavaDoc variableValue = parameter.get(variable);
395             if ( variableValue != null && !(variableValue instanceof NullValue) ) {
396                  super.render(buffer, parameter, index);
397             }
398         }
399     }
400
401     class Variable implements TemplateFragment {
402         private String JavaDoc name;
403         private String JavaDoc[] allowedContentTypes;
404         private boolean required;
405
406         public Variable(String JavaDoc name, boolean required) {
407             this.name = name;
408             this.required = required;
409         }
410
411         public Variable(String JavaDoc name, String JavaDoc []allowedContentType, boolean required) {
412             this.name = name;
413             this.allowedContentTypes = allowedContentType;
414             this.required = required;
415         }
416
417         public void render(StringBuffer JavaDoc buffer, Map JavaDoc parameter, int index) throws ProcessException {
418             Object JavaDoc variableValue = parameter.get(name);
419             if ( variableValue == null ) variableValue = new NullValue();
420             if ( variableValue instanceof ArrayValue ) {
421                 Value []array = (((ArrayValue)variableValue).getArray());
422                 if ( index > array.length-1 ) {
423                     variableValue = array[index % array.length];
424                 } else {
425                     variableValue = array[index];
426                 }
427             }
428             if ( (required && variableValue instanceof NullValue )) {
429                 throw new ProcessException(new ErrorMessage("templateRenderer/unsetValueNotAllowed", new Object JavaDoc[] { name }));
430             }
431             if ( allowedContentTypes != null && !ContentType.matches(allowedContentTypes, ((Value)variableValue).getContentType())) {
432                 throw new ProcessException(new ErrorMessage("templateRenderer/contentTypeMismatch", new Object JavaDoc[] { name, ContentType.getContentTypesAsString(allowedContentTypes), ((Value)variableValue).getContentType() }));
433             }
434             if ( variableValue instanceof PrintableValue ) {
435                 ((PrintableValue)variableValue).print(buffer);
436             } else {
437                 buffer.append(variableValue);
438             }
439         }
440     }
441 }
Popular Tags