1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.tiles.definition.digester;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.net.URL;
27 import java.util.LinkedHashMap;
28 import java.util.Map;
29
30 import org.apache.commons.digester.Digester;
31 import org.apache.commons.digester.Rule;
32 import org.apache.tiles.Attribute;
33 import org.apache.tiles.Definition;
34 import org.apache.tiles.Expression;
35 import org.apache.tiles.ListAttribute;
36 import org.apache.tiles.definition.DefinitionsFactoryException;
37 import org.apache.tiles.definition.DefinitionsReader;
38 import org.xml.sax.Attributes;
39 import org.xml.sax.ErrorHandler;
40 import org.xml.sax.SAXException;
41 import org.xml.sax.SAXParseException;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class DigesterDefinitionsReader implements DefinitionsReader {
70
71
72
73
74 public static final String PARSER_VALIDATE_PARAMETER_NAME =
75 "org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE";
76
77
78
79
80
81
82 private static final String DEFINITION_TAG = "tiles-definitions/definition";
83
84
85
86
87 private static final String PUT_TAG = "*/definition/put-attribute";
88
89
90
91
92 private static final String PUT_DEFINITION_TAG = "*/put-attribute/definition";
93
94
95
96
97 private static final String ADD_DEFINITION_TAG = "*/add-attribute/definition";
98
99
100
101
102
103 private static final String DEF_LIST_TAG = "*/definition/put-list-attribute";
104
105
106
107
108 private static final String ADD_LIST_ELE_TAG = "*/add-attribute";
109
110
111
112
113 private static final String NESTED_LIST = "*/add-list-attribute";
114
115
116
117
118
119
120
121
122 protected static final String DEFINITION_HANDLER_CLASS =
123 Definition.class.getName();
124
125
126
127
128
129
130 protected static final String PUT_ATTRIBUTE_HANDLER_CLASS =
131 Attribute.class.getName();
132
133
134
135
136
137
138 protected static final String LIST_HANDLER_CLASS =
139 ListAttribute.class.getName();
140
141
142
143
144
145
146 public static class FillDefinitionRule extends Rule {
147
148
149 @Override
150 public void begin(String namespace, String name, Attributes attributes) {
151 Definition definition = (Definition) digester.peek();
152 definition.setName(attributes.getValue("name"));
153 definition.setPreparer(attributes.getValue("preparer"));
154 String extendsAttribute = attributes.getValue("extends");
155 definition.setExtends(extendsAttribute);
156
157 String template = attributes.getValue("template");
158 Attribute attribute = Attribute.createTemplateAttribute(template);
159 attribute.setExpressionObject(Expression
160 .createExpressionFromDescribedExpression(attributes
161 .getValue("templateExpression")));
162 attribute.setRole(attributes.getValue("role"));
163 String templateType = attributes.getValue("templateType");
164 if (templateType != null) {
165 attribute.setRenderer(templateType);
166 } else if (extendsAttribute != null && templateType == null) {
167 attribute.setRenderer(null);
168 }
169 definition.setTemplateAttribute(attribute);
170 }
171 }
172
173
174
175
176
177
178 public static class FillAttributeRule extends Rule {
179
180
181 @Override
182 public void begin(String namespace, String name, Attributes attributes) {
183 Attribute attribute = (Attribute) digester.peek();
184 attribute.setValue(attributes.getValue("value"));
185 String expression = attributes.getValue("expression");
186 attribute.setExpressionObject(Expression
187 .createExpressionFromDescribedExpression(expression));
188 attribute.setRole(attributes.getValue("role"));
189 attribute.setRenderer(attributes.getValue("type"));
190 }
191 }
192
193
194
195
196
197
198
199 public static class PutAttributeRule extends Rule {
200
201
202 @Override
203 public void begin(String namespace, String name, Attributes attributes) {
204 Attribute attribute = (Attribute) digester.peek(0);
205 Definition definition = (Definition) digester.peek(1);
206 definition.putAttribute(attributes.getValue("name"), attribute,
207 "true".equals(attributes.getValue("cascade")));
208 }
209 }
210
211
212
213
214
215
216
217 public class AddNestedDefinitionRule extends Rule {
218
219
220 @Override
221 public void begin(String namespace, String name, Attributes attributes) {
222 Definition definition = (Definition) digester.peek(0);
223 if (definition.getName() == null) {
224 definition.setName(getNextUniqueDefinitionName(definitions));
225 }
226 Attribute attribute = (Attribute) digester.peek(1);
227 attribute.setValue(definition.getName());
228 attribute.setRenderer("definition");
229 }
230 }
231
232
233
234
235
236 protected Digester digester;
237
238
239
240
241
242
243 protected String[] registrations;
244
245
246
247
248 private Map<String, Definition> definitions;
249
250
251
252
253
254 private int anonymousDefinitionIndex = 1;
255
256
257
258
259 public DigesterDefinitionsReader() {
260 digester = new Digester();
261 digester.setNamespaceAware(true);
262 digester.setUseContextClassLoader(true);
263 digester.setErrorHandler(new ThrowingErrorHandler());
264
265
266 String[] registrations = getRegistrations();
267 for (int i = 0; i < registrations.length; i += 2) {
268 URL url = this.getClass().getResource(
269 registrations[i + 1]);
270 if (url != null) {
271 digester.register(registrations[i], url.toString());
272 }
273 }
274
275 initSyntax(digester);
276 }
277
278
279
280
281
282
283
284
285 public void setValidating(boolean validating) {
286 digester.setValidating(validating);
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301 public Map<String, Definition> read(Object source) {
302
303
304
305 definitions = new LinkedHashMap<String, Definition>();
306
307 if (source == null) {
308
309 return null;
310 }
311
312 InputStream input;
313 try {
314 input = (InputStream) source;
315 } catch (ClassCastException e) {
316 throw new DefinitionsFactoryException(
317 "Invalid source type. Requires java.io.InputStream.", e);
318 }
319
320 try {
321
322
323 digester.push(this);
324
325 digester.parse(input);
326
327 } catch (SAXException e) {
328 throw new DefinitionsFactoryException(
329 "XML error reading definitions.", e);
330 } catch (IOException e) {
331 throw new DefinitionsFactoryException(
332 "I/O Error reading definitions.", e);
333 } finally {
334 digester.clear();
335 }
336
337 return definitions;
338 }
339
340
341
342
343
344
345
346 protected void initSyntax(Digester digester) {
347 initDigesterForTilesDefinitionsSyntax(digester);
348 }
349
350
351
352
353
354
355
356 private void initDigesterForTilesDefinitionsSyntax(Digester digester) {
357
358 digester.addObjectCreate(DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
359 digester.addRule(DEFINITION_TAG, new FillDefinitionRule());
360 digester.addSetNext(DEFINITION_TAG, "addDefinition", DEFINITION_HANDLER_CLASS);
361
362
363 digester.addObjectCreate(PUT_DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
364 digester.addRule(PUT_DEFINITION_TAG, new FillDefinitionRule());
365 digester.addSetRoot(PUT_DEFINITION_TAG, "addDefinition");
366 digester.addRule(PUT_DEFINITION_TAG, new AddNestedDefinitionRule());
367 digester.addObjectCreate(ADD_DEFINITION_TAG, DEFINITION_HANDLER_CLASS);
368 digester.addRule(ADD_DEFINITION_TAG, new FillDefinitionRule());
369 digester.addSetRoot(ADD_DEFINITION_TAG, "addDefinition");
370 digester.addRule(ADD_DEFINITION_TAG, new AddNestedDefinitionRule());
371
372
373
374
375
376
377 digester.addObjectCreate(PUT_TAG, PUT_ATTRIBUTE_HANDLER_CLASS);
378 digester.addRule(PUT_TAG, new FillAttributeRule());
379 digester.addRule(PUT_TAG, new PutAttributeRule());
380
381
382 digester.addObjectCreate(DEF_LIST_TAG, LIST_HANDLER_CLASS);
383 digester.addSetProperties(DEF_LIST_TAG);
384 digester.addRule(DEF_LIST_TAG, new PutAttributeRule());
385
386
387
388 digester.addObjectCreate(ADD_LIST_ELE_TAG, PUT_ATTRIBUTE_HANDLER_CLASS);
389 digester.addRule(ADD_LIST_ELE_TAG, new FillAttributeRule());
390 digester.addSetNext(ADD_LIST_ELE_TAG, "add", PUT_ATTRIBUTE_HANDLER_CLASS);
391
392
393
394 digester.addObjectCreate(NESTED_LIST, LIST_HANDLER_CLASS);
395 digester.addSetProperties(NESTED_LIST);
396 digester.addSetNext(NESTED_LIST, "add", PUT_ATTRIBUTE_HANDLER_CLASS);
397 }
398
399
400
401
402
403
404
405 public void addDefinition(Definition definition) {
406 String name = definition.getName();
407 if (name == null) {
408 throw new DigesterDefinitionsReaderException(
409 "A root definition has been defined with no name");
410 }
411
412 definitions.put(name, definition);
413 }
414
415
416
417
418 private static class ThrowingErrorHandler implements ErrorHandler {
419
420
421 public void warning(SAXParseException exception) throws SAXException {
422 throw exception;
423 }
424
425
426 public void error(SAXParseException exception) throws SAXException {
427 throw exception;
428 }
429
430
431 public void fatalError(SAXParseException exception) throws SAXException {
432 throw exception;
433 }
434 }
435
436
437
438
439
440
441
442
443 protected String[] getRegistrations() {
444 if (registrations == null) {
445 registrations = new String[] {
446 "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN",
447 "/org/apache/tiles/resources/tiles-config_3_0.dtd"};
448 }
449 return registrations;
450 }
451
452
453
454
455
456
457
458
459 protected String getNextUniqueDefinitionName(
460 Map<String, Definition> definitions) {
461 String candidate;
462
463 do {
464 candidate = "$anonymousDefinition" + anonymousDefinitionIndex;
465 anonymousDefinitionIndex++;
466 } while (definitions.containsKey(candidate));
467
468 return candidate;
469 }
470 }