2009/05/20 - Apache Shale has been retired.
For more information, please explore the Attic.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.shale.clay.parser.builder;
22
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.shale.clay.config.beans.ActionListenerBean;
30 import org.apache.shale.clay.config.beans.AttributeBean;
31 import org.apache.shale.clay.config.beans.ComponentBean;
32 import org.apache.shale.clay.config.beans.ConfigBean;
33 import org.apache.shale.clay.config.beans.ConfigBeanFactory;
34 import org.apache.shale.clay.config.beans.ConverterBean;
35 import org.apache.shale.clay.config.beans.ElementBean;
36 import org.apache.shale.clay.config.beans.SymbolBean;
37 import org.apache.shale.clay.config.beans.ValidatorBean;
38 import org.apache.shale.clay.config.beans.ValueChangeListenerBean;
39 import org.apache.shale.clay.parser.Node;
40
41 /***
42 * <p>This class handles building the {@link org.apache.shale.clay.config.beans.ElementBean}'s
43 * from the html markup resembling the <attributes> node in the clay
44 * DTD, http://shale.apache.org/dtds/clay-config_1_0.dtd.</p>
45 */
46 public class ElementBuilder extends Builder {
47
48 /***
49 * <p>Common Logger utility class.</p>
50 */
51 private static Log log;
52 static {
53 log = LogFactory.getLog(ElementBuilder.class);
54 }
55
56
57 /***
58 * <p>Returns the <code>jsfid</code> from the target HTML
59 * {@link org.apache.shale.clay.parser.Node}.</p>
60 *
61 * @param node markup
62 * @return jsfid
63 */
64 protected String getJsfid(Node node) {
65 String jsfid = (String) node.getAttributes().get("jsfid");
66 return jsfid;
67 }
68
69 /***
70 * <p>Returns the <code>componentType</code> from the target HTML
71 * {@link org.apache.shale.clay.parser.Node}.</p>
72 *
73 * @param node markup
74 * @return component type
75 */
76 protected String getComponentType(Node node) {
77 String componentType = (String) node.getAttributes().get("componentType");
78 return componentType;
79 }
80
81 /***
82 * <p>Adds a {@link org.apache.shale.clay.config.beans.ConverterBean}
83 * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
84 * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
85 *
86 * @param node markup
87 * @param target child config bean
88 */
89 protected void addConverter(Node node, ElementBean target) {
90 ConverterBean targetConverter = new ConverterBean();
91
92 String jsfid = getJsfid(node);
93 targetConverter.setJsfid(jsfid);
94
95
96 realizeComponent(node, targetConverter);
97
98 target.addConverter(targetConverter);
99
100 }
101
102
103 /***
104 * <p>Adds a {@link org.apache.shale.clay.config.beans.ValidatorBean}
105 * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
106 * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
107 *
108 * @param node markup
109 * @param target child config bean
110 */
111 protected void addValidator(Node node, ElementBean target) {
112 ValidatorBean targetValidator = new ValidatorBean();
113
114 String jsfid = getJsfid(node);
115 targetValidator.setJsfid(jsfid);
116
117
118 realizeComponent(node, targetValidator);
119
120 target.addValidator(targetValidator);
121
122 }
123
124 /***
125 * <p>Adds an {@link org.apache.shale.clay.config.beans.ActionListenerBean}
126 * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
127 * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
128 *
129 * @param node markup
130 * @param target child config bean
131 */
132 protected void addActionListener(Node node, ElementBean target) {
133 ActionListenerBean targetActionListener = new ActionListenerBean();
134
135 String jsfid = getJsfid(node);
136 targetActionListener.setJsfid(jsfid);
137
138
139 realizeComponent(node, targetActionListener);
140
141 target.addActionListener(targetActionListener);
142
143 }
144
145 /***
146 * <p>Adds a {@link org.apache.shale.clay.config.beans.ActionListenerBean}
147 * to the <code>target</code> {@link org.apache.shale.clay.config.beans.ElementBean}
148 * using the {@link org.apache.shale.clay.parser.Node} as the input source.</p>
149 *
150 * @param node markup
151 * @param target child config bean
152 */
153 protected void addValueChangeListener(Node node, ElementBean target) {
154 ValueChangeListenerBean targetValueChangeListener = new ValueChangeListenerBean();
155
156 String jsfid = getJsfid(node);
157 targetValueChangeListener.setJsfid(jsfid);
158
159
160 realizeComponent(node, targetValueChangeListener);
161
162 target.addValueChangeListener(targetValueChangeListener);
163 }
164
165
166 /***
167 * <p>Realizes the inheritance of the <code>target</code>
168 * {@link org.apache.shale.clay.config.beans.ComponentBean} and
169 * and then applies attributes that are optionally nested
170 * under the <code>node</code>.</p>
171 *
172 * @param node markup
173 * @param target child config bean
174 */
175 protected void realizeComponent(Node node, ComponentBean target) {
176
177 ConfigBean config = ConfigBeanFactory.findConfig(target.getJsfid());
178
179 try {
180
181 config.assignParent(target);
182
183 config.realizingInheritance(target);
184 } catch (RuntimeException e) {
185 log.error(e);
186 throw new RuntimeException(
187 messages.getMessage("parser.unresolved",
188 new Object[] {node.getToken(), node.getToken().getRawText()}));
189 }
190
191 assignAttributes(node, target);
192
193
194 Iterator ci = node.getChildren().iterator();
195 while (ci.hasNext()) {
196 Node child = (Node) ci.next();
197 if (child.isWellFormed() && child.getName() != null
198 && child.getName().equals("attributes")) {
199
200 addAttributes(child, target);
201 }
202 }
203
204 }
205
206
207 /***
208 * <p>Looks for <set/> nodes within a <attributes> node and
209 * converting them to {@link org.apache.shale.clay.config.beans.AttributeBean}'s
210 * on the <code>target</code> {@link org.apache.shale.clay.config.beans.ComponentBean}.
211 * </p>
212 *
213 * @param attributesNode markup
214 * @param target child config bean
215 */
216 protected void addAttributes(Node attributesNode, ComponentBean target) {
217 Iterator ci = attributesNode.getChildren().iterator();
218 while (ci.hasNext()) {
219 Node child = (Node) ci.next();
220 if (child.isWellFormed() && child.getName() != null
221 && child.getName().equals("set")) {
222
223 String name = (String) child.getAttributes().get("name");
224 String value = (String) child.getAttributes().get("value");
225 String bindingType = (String) child.getAttributes().get("bindingType");
226
227 AttributeBean attr = target.getAttribute(name);
228 if (attr != null) {
229 createAttribute(attr, value, target);
230 } else {
231 attr = new AttributeBean();
232 attr.setName(name);
233 attr.setValue(value);
234 attr.setBindingType(bindingType);
235 target.addAttribute(attr);
236 }
237 }
238 }
239 }
240
241
242 /***
243 * <p>Adds markup <code>symbols</code> to the <code>target</code>
244 * {@link org.apache.shale.clay.config.beans.ElementBean}.
245 * </p>
246 *
247 * @param symbolsNode markup
248 * @param target child config bean
249 */
250 protected void addSymbols(Node symbolsNode, ElementBean target) {
251 Iterator si = symbolsNode.getChildren().iterator();
252 while (si.hasNext()) {
253 Node child = (Node) si.next();
254 if (child.isWellFormed() && child.getName() != null
255 && child.getName().equals("set")) {
256
257 String name = (String) child.getAttributes().get("name");
258 String value = (String) child.getAttributes().get("value");
259
260 if (name != null && name.length() > 0) {
261 SymbolBean symbol = new SymbolBean();
262 StringBuffer tmp = new StringBuffer(name);
263 if (tmp.charAt(0) != '@') {
264 tmp.insert(0, '@');
265 }
266
267 symbol.setName(tmp.toString());
268 symbol.setValue(value);
269 target.addSymbol(symbol);
270 }
271 }
272 }
273 }
274
275
276
277 /***
278 * <p>Handles converting markup resembling the <element> node
279 * in the clay DTD, http://shale.apache.org/dtds/clay-config_1_0.dtd,
280 * to the target {@link org.apache.shale.clay.config.beans.ElementBean}.</p>
281 *
282 * @param node markup
283 * @param target child config bean
284 * @param root parent config bean
285 */
286 protected void encodeBegin(Node node, ElementBean target, ComponentBean root) {
287 super.encodeBegin(node, target, root);
288
289 List deleteList = new ArrayList();
290 Iterator ci = node.getChildren().iterator();
291 while (ci.hasNext()) {
292 Node child = (Node) ci.next();
293 if (child.isWellFormed() && child.getName() != null) {
294 if (child.getName().equals("attributes")) {
295 addAttributes(child, target);
296 deleteList.add(child);
297 } else if (child.getName().equals("symbols")) {
298 addSymbols(child, target);
299 deleteList.add(child);
300 } else if (child.getName().equals("converter")) {
301 addConverter(child, target);
302 deleteList.add(child);
303 } else if (child.getName().equals("validator")) {
304 addValidator(child, target);
305 deleteList.add(child);
306 } else if (child.getName().equals("actionListener")) {
307 addActionListener(child, target);
308 deleteList.add(child);
309 } else if (child.getName().equals("valueChangeListener")) {
310 addValueChangeListener(child, target);
311 deleteList.add(child);
312 }
313 } else {
314 if (child.isComment() || isNodeWhitespace(child)) {
315
316 deleteList.add(child);
317 }
318 }
319 }
320
321 ci = deleteList.iterator();
322 while (ci.hasNext()) {
323 node.getChildren().remove(ci.next());
324 }
325
326 }
327
328
329 /***
330 * <p>This method is overridden to look for a <code>renderId</code>
331 * attribute in the {@link org.apache.shale.clay.parser.Node}.
332 * If one exists, it is applied to the target
333 * {@link org.apache.shale.clay.config.beans.ElementBean}. The
334 * super class {@link Builder} generates a unique id by default.
335 * The clay namespace HTML nodes can override the renderId to
336 * allow overridding of nested elements.</p>
337 *
338 * @param node markup
339 * @return config bean
340 */
341 public ElementBean createElement(Node node) {
342 ElementBean target = super.createElement(node);
343 String renderId = (String) node.getAttributes().get("renderId");
344 if (renderId != null) {
345 Integer id = null;
346 try {
347 id = Integer.valueOf(renderId);
348 } catch (NumberFormatException e) {
349 log.error(e);
350 throw new RuntimeException(
351 messages.getMessage("parser.unresolved",
352 new Object[] {node.getToken(), node.getToken().getRawText()}));
353 }
354 if (id != null) {
355 target.setRenderId(id.intValue());
356 }
357 }
358
359 return target;
360 }
361
362 /***
363 * <p>
364 * This override returns <code>true</code> indicating that the from JSF
365 * component can have children.
366 * </p>
367 *
368 * @return <code>true</code>
369 */
370 public boolean isChildrenAllowed() {
371 return true;
372 }
373
374
375 /***
376 * <p>
377 * This method resolves the <code>jsfid</code> attribute for an HTML
378 * element to a component definition in the XML configuration files.
379 * </p>
380 *
381 * @param node markup
382 * @param target child config bean
383 */
384 protected void assignNode(Node node, ElementBean target) {
385
386
387 String id = (String) node.getAttributes().get("id");
388 target.setId(id);
389
390
391 if (target.getJsfid() != null) {
392
393 ConfigBean config = ConfigBeanFactory.findConfig(target.getJsfid());
394
395 target.setComponentType(null);
396
397
398 try {
399
400 config.assignParent(target);
401
402 config.realizingInheritance(target);
403 } catch (RuntimeException e) {
404 log.error(e);
405 throw new RuntimeException(
406 messages.getMessage("parser.unresolved",
407 new Object[] {node.getToken(), node.getToken().getRawText()}));
408 }
409
410
411 if (target.getComponentType() == null) {
412 target.setComponentType(this.getComponentType(node));
413 }
414
415 }
416
417
418 assignAttributes(node, target);
419
420 }
421
422
423 /***
424 * <p>Test the value of the node and returns <code>true</code> if
425 * the value is only whitespace.</p>
426 *
427 * @param node markup node
428 * @return <code>true</code> if value of the node is only whitespace
429 */
430 protected boolean isNodeWhitespace(Node node) {
431 StringBuffer document = node.getToken().getDocument();
432 for (int i = node.getToken().getBeginOffset();
433 i < node.getToken().getEndOffset(); i++) {
434 char c = document.charAt(i);
435 if (!Character.isWhitespace(c)) {
436 return false;
437 }
438 }
439 return true;
440 }
441
442 }