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 | 7 | 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 | 1 | protected static final String DEFINITION_HANDLER_CLASS = |
123 | |
Definition.class.getName(); |
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | 1 | protected static final String PUT_ATTRIBUTE_HANDLER_CLASS = |
131 | |
Attribute.class.getName(); |
132 | |
|
133 | |
|
134 | |
|
135 | |
|
136 | |
|
137 | |
|
138 | 1 | protected static final String LIST_HANDLER_CLASS = |
139 | |
ListAttribute.class.getName(); |
140 | |
|
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | 93 | public static class FillDefinitionRule extends Rule { |
147 | |
|
148 | |
|
149 | |
@Override |
150 | |
public void begin(String namespace, String name, Attributes attributes) { |
151 | 412 | Definition definition = (Definition) digester.peek(); |
152 | 412 | definition.setName(attributes.getValue("name")); |
153 | 412 | definition.setPreparer(attributes.getValue("preparer")); |
154 | 412 | String extendsAttribute = attributes.getValue("extends"); |
155 | 412 | definition.setExtends(extendsAttribute); |
156 | |
|
157 | 412 | String template = attributes.getValue("template"); |
158 | 412 | Attribute attribute = Attribute.createTemplateAttribute(template); |
159 | 412 | attribute.setExpressionObject(Expression |
160 | |
.createExpressionFromDescribedExpression(attributes |
161 | |
.getValue("templateExpression"))); |
162 | 412 | attribute.setRole(attributes.getValue("role")); |
163 | 412 | String templateType = attributes.getValue("templateType"); |
164 | 412 | if (templateType != null) { |
165 | 6 | attribute.setRenderer(templateType); |
166 | 406 | } else if (extendsAttribute != null && templateType == null) { |
167 | 32 | attribute.setRenderer(null); |
168 | |
} |
169 | 412 | definition.setTemplateAttribute(attribute); |
170 | 412 | } |
171 | |
} |
172 | |
|
173 | |
|
174 | |
|
175 | |
|
176 | |
|
177 | |
|
178 | 62 | public static class FillAttributeRule extends Rule { |
179 | |
|
180 | |
|
181 | |
@Override |
182 | |
public void begin(String namespace, String name, Attributes attributes) { |
183 | 2011 | Attribute attribute = (Attribute) digester.peek(); |
184 | 2011 | attribute.setValue(attributes.getValue("value")); |
185 | 2011 | String expression = attributes.getValue("expression"); |
186 | 2011 | attribute.setExpressionObject(Expression |
187 | |
.createExpressionFromDescribedExpression(expression)); |
188 | 2011 | attribute.setRole(attributes.getValue("role")); |
189 | 2011 | attribute.setRenderer(attributes.getValue("type")); |
190 | 2011 | } |
191 | |
} |
192 | |
|
193 | |
|
194 | |
|
195 | |
|
196 | |
|
197 | |
|
198 | |
|
199 | 62 | public static class PutAttributeRule extends Rule { |
200 | |
|
201 | |
|
202 | |
@Override |
203 | |
public void begin(String namespace, String name, Attributes attributes) { |
204 | 2006 | Attribute attribute = (Attribute) digester.peek(0); |
205 | 2006 | Definition definition = (Definition) digester.peek(1); |
206 | 2006 | definition.putAttribute(attributes.getValue("name"), attribute, |
207 | |
"true".equals(attributes.getValue("cascade"))); |
208 | 2006 | } |
209 | |
} |
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
|
215 | |
|
216 | |
|
217 | 62 | public class AddNestedDefinitionRule extends Rule { |
218 | |
|
219 | |
|
220 | |
@Override |
221 | |
public void begin(String namespace, String name, Attributes attributes) { |
222 | 7 | Definition definition = (Definition) digester.peek(0); |
223 | 7 | if (definition.getName() == null) { |
224 | 7 | definition.setName(getNextUniqueDefinitionName(definitions)); |
225 | |
} |
226 | 7 | Attribute attribute = (Attribute) digester.peek(1); |
227 | 7 | attribute.setValue(definition.getName()); |
228 | 7 | attribute.setRenderer("definition"); |
229 | 7 | } |
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 | 31 | private int anonymousDefinitionIndex = 1; |
255 | |
|
256 | |
|
257 | |
|
258 | |
|
259 | 31 | public DigesterDefinitionsReader() { |
260 | 31 | digester = new Digester(); |
261 | 31 | digester.setNamespaceAware(true); |
262 | 31 | digester.setUseContextClassLoader(true); |
263 | 31 | digester.setErrorHandler(new ThrowingErrorHandler()); |
264 | |
|
265 | |
|
266 | 31 | String[] registrations = getRegistrations(); |
267 | 62 | for (int i = 0; i < registrations.length; i += 2) { |
268 | 31 | URL url = this.getClass().getResource( |
269 | |
registrations[i + 1]); |
270 | 31 | if (url != null) { |
271 | 31 | digester.register(registrations[i], url.toString()); |
272 | |
} |
273 | |
} |
274 | |
|
275 | 31 | initSyntax(digester); |
276 | 31 | } |
277 | |
|
278 | |
|
279 | |
|
280 | |
|
281 | |
|
282 | |
|
283 | |
|
284 | |
|
285 | |
public void setValidating(boolean validating) { |
286 | 1 | digester.setValidating(validating); |
287 | 1 | } |
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 | 184 | definitions = new LinkedHashMap<String, Definition>(); |
306 | |
|
307 | 184 | if (source == null) { |
308 | |
|
309 | 1 | return null; |
310 | |
} |
311 | |
|
312 | |
InputStream input; |
313 | |
try { |
314 | 183 | input = (InputStream) source; |
315 | 1 | } catch (ClassCastException e) { |
316 | 1 | throw new DefinitionsFactoryException( |
317 | |
"Invalid source type. Requires java.io.InputStream.", e); |
318 | 182 | } |
319 | |
|
320 | |
try { |
321 | |
|
322 | |
|
323 | 182 | digester.push(this); |
324 | |
|
325 | 182 | digester.parse(input); |
326 | |
|
327 | 2 | } catch (SAXException e) { |
328 | 2 | throw new DefinitionsFactoryException( |
329 | |
"XML error reading definitions.", e); |
330 | 0 | } catch (IOException e) { |
331 | 0 | throw new DefinitionsFactoryException( |
332 | |
"I/O Error reading definitions.", e); |
333 | |
} finally { |
334 | 182 | digester.clear(); |
335 | 180 | } |
336 | |
|
337 | 180 | return definitions; |
338 | |
} |
339 | |
|
340 | |
|
341 | |
|
342 | |
|
343 | |
|
344 | |
|
345 | |
|
346 | |
protected void initSyntax(Digester digester) { |
347 | 31 | initDigesterForTilesDefinitionsSyntax(digester); |
348 | 31 | } |
349 | |
|
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
|
355 | |
|
356 | |
private void initDigesterForTilesDefinitionsSyntax(Digester digester) { |
357 | |
|
358 | 31 | digester.addObjectCreate(DEFINITION_TAG, DEFINITION_HANDLER_CLASS); |
359 | 31 | digester.addRule(DEFINITION_TAG, new FillDefinitionRule()); |
360 | 31 | digester.addSetNext(DEFINITION_TAG, "addDefinition", DEFINITION_HANDLER_CLASS); |
361 | |
|
362 | |
|
363 | 31 | digester.addObjectCreate(PUT_DEFINITION_TAG, DEFINITION_HANDLER_CLASS); |
364 | 31 | digester.addRule(PUT_DEFINITION_TAG, new FillDefinitionRule()); |
365 | 31 | digester.addSetRoot(PUT_DEFINITION_TAG, "addDefinition"); |
366 | 31 | digester.addRule(PUT_DEFINITION_TAG, new AddNestedDefinitionRule()); |
367 | 31 | digester.addObjectCreate(ADD_DEFINITION_TAG, DEFINITION_HANDLER_CLASS); |
368 | 31 | digester.addRule(ADD_DEFINITION_TAG, new FillDefinitionRule()); |
369 | 31 | digester.addSetRoot(ADD_DEFINITION_TAG, "addDefinition"); |
370 | 31 | digester.addRule(ADD_DEFINITION_TAG, new AddNestedDefinitionRule()); |
371 | |
|
372 | |
|
373 | |
|
374 | |
|
375 | |
|
376 | |
|
377 | 31 | digester.addObjectCreate(PUT_TAG, PUT_ATTRIBUTE_HANDLER_CLASS); |
378 | 31 | digester.addRule(PUT_TAG, new FillAttributeRule()); |
379 | 31 | digester.addRule(PUT_TAG, new PutAttributeRule()); |
380 | |
|
381 | |
|
382 | 31 | digester.addObjectCreate(DEF_LIST_TAG, LIST_HANDLER_CLASS); |
383 | 31 | digester.addSetProperties(DEF_LIST_TAG); |
384 | 31 | digester.addRule(DEF_LIST_TAG, new PutAttributeRule()); |
385 | |
|
386 | |
|
387 | |
|
388 | 31 | digester.addObjectCreate(ADD_LIST_ELE_TAG, PUT_ATTRIBUTE_HANDLER_CLASS); |
389 | 31 | digester.addRule(ADD_LIST_ELE_TAG, new FillAttributeRule()); |
390 | 31 | digester.addSetNext(ADD_LIST_ELE_TAG, "add", PUT_ATTRIBUTE_HANDLER_CLASS); |
391 | |
|
392 | |
|
393 | |
|
394 | 31 | digester.addObjectCreate(NESTED_LIST, LIST_HANDLER_CLASS); |
395 | 31 | digester.addSetProperties(NESTED_LIST); |
396 | 31 | digester.addSetNext(NESTED_LIST, "add", PUT_ATTRIBUTE_HANDLER_CLASS); |
397 | 31 | } |
398 | |
|
399 | |
|
400 | |
|
401 | |
|
402 | |
|
403 | |
|
404 | |
|
405 | |
public void addDefinition(Definition definition) { |
406 | 413 | String name = definition.getName(); |
407 | 413 | if (name == null) { |
408 | 1 | throw new DigesterDefinitionsReaderException( |
409 | |
"A root definition has been defined with no name"); |
410 | |
} |
411 | |
|
412 | 412 | definitions.put(name, definition); |
413 | 412 | } |
414 | |
|
415 | |
|
416 | |
|
417 | |
|
418 | 62 | private static class ThrowingErrorHandler implements ErrorHandler { |
419 | |
|
420 | |
|
421 | |
public void warning(SAXParseException exception) throws SAXException { |
422 | 0 | throw exception; |
423 | |
} |
424 | |
|
425 | |
|
426 | |
public void error(SAXParseException exception) throws SAXException { |
427 | 1 | throw exception; |
428 | |
} |
429 | |
|
430 | |
|
431 | |
public void fatalError(SAXParseException exception) throws SAXException { |
432 | 1 | throw exception; |
433 | |
} |
434 | |
} |
435 | |
|
436 | |
|
437 | |
|
438 | |
|
439 | |
|
440 | |
|
441 | |
|
442 | |
|
443 | |
protected String[] getRegistrations() { |
444 | 31 | if (registrations == null) { |
445 | 31 | 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 | 31 | 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 | 7 | candidate = "$anonymousDefinition" + anonymousDefinitionIndex; |
465 | 7 | anonymousDefinitionIndex++; |
466 | 7 | } while (definitions.containsKey(candidate)); |
467 | |
|
468 | 7 | return candidate; |
469 | |
} |
470 | |
} |