1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.datadictionary.parse;
17
18 import com.sun.org.apache.xml.internal.serialize.Method;
19 import com.sun.org.apache.xml.internal.serialize.OutputFormat;
20 import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
21 import org.apache.commons.lang.StringUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.springframework.beans.factory.config.BeanDefinition;
25 import org.springframework.beans.factory.config.BeanDefinitionHolder;
26 import org.springframework.beans.factory.config.RuntimeBeanReference;
27 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
28 import org.springframework.beans.factory.support.ManagedList;
29 import org.springframework.beans.factory.support.ManagedMap;
30 import org.springframework.beans.factory.support.ManagedSet;
31 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
32 import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
33 import org.springframework.beans.factory.xml.ParserContext;
34 import org.springframework.util.xml.DomUtils;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.NamedNodeMap;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.NodeList;
40
41 import java.io.IOException;
42 import java.io.StringWriter;
43 import java.util.ArrayList;
44 import java.util.Map;
45 import java.util.Set;
46
47
48
49
50
51
52 public class CustomSchemaParser extends AbstractSingleBeanDefinitionParser {
53 private static final Log LOG = LogFactory.getLog(CustomSchemaParser.class);
54
55 private static final String INC_TAG = "inc";
56
57 private static int beanNumber = 0;
58
59
60
61
62
63
64
65 @Override
66 protected Class<?> getBeanClass(Element bean) {
67 Map<String, BeanTagInfo> beanType = CustomTagAnnotations.getBeanTags();
68
69 if (!beanType.containsKey(bean.getLocalName())) {
70 return null;
71 }
72
73
74 return beanType.get(bean.getLocalName()).getBeanClass();
75 }
76
77
78
79
80
81
82
83
84
85 @Override
86 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder bean) {
87
88 Map<String, Map<String, BeanTagAttributeInfo>> attributeProperties =
89 CustomTagAnnotations.getAttributeProperties();
90 Map<String, BeanTagAttributeInfo> entries = attributeProperties.get(element.getLocalName());
91
92
93 if (entries == null) {
94 LOG.error("Bean Tag not found " + element.getLocalName());
95 }
96
97 if (element.getTagName().equals(INC_TAG)) {
98 String parentId = element.getAttribute("compId");
99 bean.setParentName(parentId);
100
101 return;
102 }
103
104 if (element.getTagName().equals("content")) {
105 bean.setParentName("Uif-Content");
106
107 String markup = nodesToString(element.getChildNodes());
108 bean.addPropertyValue("markup", markup);
109
110 return;
111 }
112
113
114 BeanTagInfo tagInfo = CustomTagAnnotations.getBeanTags().get(element.getLocalName());
115
116 String elementParent = element.getAttribute("parent");
117 if (StringUtils.isNotBlank(elementParent) && !StringUtils.equals(elementParent, tagInfo.getParent())) {
118 bean.setParentName(elementParent);
119 } else if (StringUtils.isNotBlank(tagInfo.getParent())) {
120 bean.setParentName(tagInfo.getParent());
121 }
122
123
124 NamedNodeMap attributes = element.getAttributes();
125 for (int i = 0; i < attributes.getLength(); i++) {
126 processSingleValue(attributes.item(i).getNodeName(), attributes.item(i).getNodeValue(), entries, bean);
127 }
128
129 ArrayList<Element> children = (ArrayList<Element>) DomUtils.getChildElements(element);
130
131
132 for (int i = 0; i < children.size(); i++) {
133 String tag = children.get(i).getLocalName();
134 BeanTagAttributeInfo info = entries.get(tag);
135
136 if (children.get(i).getTagName().equals("spring:property") || children.get(i).getTagName().equals(
137 "property")) {
138 BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
139 delegate.parsePropertyElement(children.get(i), bean.getBeanDefinition());
140
141 continue;
142 }
143
144
145 String propertyName;
146 BeanTagAttribute.AttributeType type = null;
147 if (info == null) {
148 propertyName = CustomTagAnnotations.findPropertyByType(element.getLocalName(), tag);
149
150 if (StringUtils.isNotBlank(propertyName)) {
151 bean.addPropertyValue(propertyName, parseBean(children.get(i), bean, parserContext));
152
153 continue;
154 } else {
155
156
157 propertyName = tag;
158 type = findBeanType(children.get(i));
159 }
160 } else {
161
162 propertyName = info.getPropertyName();
163 type = info.getType();
164 }
165
166
167 ArrayList<Element> grandChildren = (ArrayList<Element>) DomUtils.getChildElements(children.get(i));
168
169 if (type == BeanTagAttribute.AttributeType.SINGLEVALUE) {
170 String propertyValue = DomUtils.getTextValue(children.get(i));
171 bean.addPropertyValue(propertyName, propertyValue);
172 } else if (type == BeanTagAttribute.AttributeType.ANY) {
173 String propertyValue = nodesToString(children.get(i).getChildNodes());
174 bean.addPropertyValue(propertyName, propertyValue);
175 } else if ((type == BeanTagAttribute.AttributeType.DIRECT) || (type
176 == BeanTagAttribute.AttributeType.DIRECTORBYTYPE)) {
177 boolean isPropertyTag = false;
178 if ((children.get(i).getAttributes().getLength() == 0) && (grandChildren.size() == 1)) {
179 String grandChildTag = grandChildren.get(0).getLocalName();
180
181 Class<?> valueClass = info.getValueType();
182 if (valueClass.isInterface()) {
183 try {
184 valueClass = Class.forName(valueClass.getName() + "Base");
185 } catch (ClassNotFoundException e) {
186 throw new RuntimeException("Unable to find impl class for interface", e);
187 }
188 }
189
190 Set<String> validTagNames = CustomTagAnnotations.getBeanTagsByClass(valueClass);
191 if (validTagNames.contains(grandChildTag)) {
192 isPropertyTag = true;
193 }
194 }
195
196 if (isPropertyTag) {
197 bean.addPropertyValue(propertyName, parseBean(grandChildren.get(0), bean, parserContext));
198 } else {
199 bean.addPropertyValue(propertyName, parseBean(children.get(i), bean, parserContext));
200 }
201 } else if ((type == BeanTagAttribute.AttributeType.SINGLEBEAN) || (type
202 == BeanTagAttribute.AttributeType.BYTYPE)) {
203 bean.addPropertyValue(propertyName, parseBean(grandChildren.get(0), bean, parserContext));
204 } else if (type == BeanTagAttribute.AttributeType.LISTBEAN) {
205 bean.addPropertyValue(propertyName, parseList(grandChildren, children.get(i), bean, parserContext));
206 } else if (type == BeanTagAttribute.AttributeType.LISTVALUE) {
207 bean.addPropertyValue(propertyName, parseList(grandChildren, children.get(i), bean, parserContext));
208 } else if (type == BeanTagAttribute.AttributeType.MAPVALUE) {
209 bean.addPropertyValue(propertyName, parseMap(grandChildren, children.get(i), bean, parserContext));
210 } else if (type == BeanTagAttribute.AttributeType.MAPBEAN) {
211 bean.addPropertyValue(propertyName, parseMap(grandChildren, children.get(i), bean, parserContext));
212 } else if (type == BeanTagAttribute.AttributeType.SETVALUE) {
213 bean.addPropertyValue(propertyName, parseSet(grandChildren, children.get(i), bean, parserContext));
214 } else if (type == BeanTagAttribute.AttributeType.SETBEAN) {
215 bean.addPropertyValue(propertyName, parseSet(grandChildren, children.get(i), bean, parserContext));
216 }
217 }
218 }
219
220
221
222
223
224
225
226
227
228 protected void processSingleValue(String name, String value, Map<String, BeanTagAttributeInfo> entries,
229 BeanDefinitionBuilder bean) {
230
231 if (name.toLowerCase().compareTo("parent") == 0) {
232
233 bean.setParentName(value);
234 } else if (name.toLowerCase().compareTo("abstract") == 0) {
235
236 bean.setAbstract(Boolean.valueOf(value));
237 } else if (name.toLowerCase().compareTo("id") == 0) {
238
239 } else {
240
241
242
243 if (name.contains("-ref")) {
244 bean.addPropertyValue(name.substring(0, name.length() - 4), new RuntimeBeanReference(value));
245 } else {
246 BeanTagAttributeInfo info = entries.get(name);
247 String propertyName;
248
249 if (info == null) {
250 propertyName = name;
251 } else {
252 propertyName = info.getName();
253 }
254 bean.addPropertyValue(propertyName, value);
255 }
256 }
257 }
258
259
260
261
262
263
264
265 protected Object findKey(Element grandchild, BeanDefinitionBuilder parent, ParserContext parserContext) {
266 String key = grandchild.getAttribute("key");
267 if (!key.isEmpty()) {
268 return key;
269 }
270
271 Element keyTag = DomUtils.getChildElementByTagName(grandchild, "key");
272 if (keyTag != null) {
273 if (DomUtils.getChildElements(keyTag).isEmpty()) {
274 return keyTag.getTextContent();
275 } else {
276 return parseBean(DomUtils.getChildElements(keyTag).get(0), parent, parserContext);
277 }
278 }
279
280 return null;
281 }
282
283
284
285
286
287
288
289 protected Object findValue(Element grandchild, BeanDefinitionBuilder parent, ParserContext parserContext) {
290 String value = grandchild.getAttribute("value");
291 if (!value.isEmpty()) {
292 return value;
293 }
294
295 Element valueTag = DomUtils.getChildElementByTagName(grandchild, "value");
296 if (valueTag != null) {
297 if (DomUtils.getChildElements(valueTag).isEmpty()) {
298 return valueTag.getTextContent();
299 } else {
300 return parseBean(DomUtils.getChildElements(valueTag).get(0), parent, parserContext);
301 }
302 }
303
304 return null;
305 }
306
307
308
309
310
311
312
313 protected BeanTagAttribute.AttributeType findBeanType(Element tag) {
314 int numberChildren = 0;
315
316
317 String overrideType = tag.getAttribute("overrideBeanType");
318 if (!StringUtils.isEmpty(overrideType)) {
319 if (overrideType.toLowerCase().compareTo("singlebean") == 0) {
320 return BeanTagAttribute.AttributeType.SINGLEBEAN;
321 }
322 if (overrideType.toLowerCase().compareTo("singlevalue") == 0) {
323 return BeanTagAttribute.AttributeType.SINGLEVALUE;
324 }
325 if (overrideType.toLowerCase().compareTo("listbean") == 0) {
326 return BeanTagAttribute.AttributeType.LISTBEAN;
327 }
328 if (overrideType.toLowerCase().compareTo("listvalue") == 0) {
329 return BeanTagAttribute.AttributeType.LISTVALUE;
330 }
331 if (overrideType.toLowerCase().compareTo("mapbean") == 0) {
332 return BeanTagAttribute.AttributeType.MAPBEAN;
333 }
334 if (overrideType.toLowerCase().compareTo("mapvalue") == 0) {
335 return BeanTagAttribute.AttributeType.MAPVALUE;
336 }
337 if (overrideType.toLowerCase().compareTo("setbean") == 0) {
338 return BeanTagAttribute.AttributeType.SETBEAN;
339 }
340 if (overrideType.toLowerCase().compareTo("setvalue") == 0) {
341 return BeanTagAttribute.AttributeType.SETVALUE;
342 }
343 }
344
345
346 numberChildren = DomUtils.getChildElementsByTagName(tag, "value").size();
347 if (numberChildren > 0) {
348 return BeanTagAttribute.AttributeType.LISTVALUE;
349 }
350
351 numberChildren = DomUtils.getChildElementsByTagName(tag, "spring:list").size();
352 if (numberChildren > 0) {
353 return BeanTagAttribute.AttributeType.LISTBEAN;
354 }
355
356 numberChildren = DomUtils.getChildElementsByTagName(tag, "spring:set").size();
357 if (numberChildren > 0) {
358 return BeanTagAttribute.AttributeType.SETBEAN;
359 }
360
361
362 numberChildren = DomUtils.getChildElementsByTagName(tag, "entry").size();
363 if (numberChildren > 0) {
364 return BeanTagAttribute.AttributeType.MAPVALUE;
365 }
366
367 numberChildren = DomUtils.getChildElementsByTagName(tag, "map").size();
368 if (numberChildren > 0) {
369 return BeanTagAttribute.AttributeType.MAPBEAN;
370 }
371
372
373 numberChildren = DomUtils.getChildElements(tag).size();
374 if (numberChildren > 1) {
375 return BeanTagAttribute.AttributeType.LISTBEAN;
376 }
377
378
379 return BeanTagAttribute.AttributeType.SINGLEBEAN;
380 }
381
382
383
384
385
386
387
388
389
390 protected Object parseBean(Element tag, BeanDefinitionBuilder parent, ParserContext parserContext) {
391 if (tag.getNamespaceURI().compareTo("http://www.springframework.org/schema/beans") == 0 || tag.getLocalName()
392 .equals("bean")) {
393 return parseSpringBean(tag, parserContext);
394 } else {
395 return parseCustomBean(tag, parent, parserContext);
396 }
397 }
398
399
400
401
402
403
404
405 protected Object parseSpringBean(Element tag, ParserContext parserContext) {
406 if (tag.getLocalName().compareTo("ref") == 0) {
407
408
409 Element temp = tag.getOwnerDocument().createElement("bean");
410 temp.setAttribute("parent", tag.getAttribute("bean"));
411 tag = temp;
412 return new RuntimeBeanReference(tag.getAttribute("parent"));
413 }
414
415
416 Document document = tag.getOwnerDocument();
417 NamedNodeMap attributes = tag.getAttributes();
418 for (int i = 0; i < attributes.getLength(); i++) {
419 Node attribute = attributes.item(i);
420 String name = attribute.getNodeName();
421 if (name.startsWith("p:")) {
422 Element property = document.createElement("property");
423 property.setAttribute("name", StringUtils.removeStart(name, "p:"));
424 property.setAttribute("value", attribute.getTextContent());
425
426 if (tag.getFirstChild() != null) {
427 tag.insertBefore(property, tag.getFirstChild());
428 } else {
429 tag.appendChild(property);
430 }
431 }
432 }
433
434
435 BeanDefinitionParserDelegate delegate = parserContext.getDelegate();
436 BeanDefinitionHolder bean = delegate.parseBeanDefinitionElement(tag);
437
438
439 String name = bean.getBeanDefinition().getParentName() + "$Customchild" + beanNumber;
440 if (tag.getAttribute("id") != null && !StringUtils.isEmpty(tag.getAttribute("id"))) {
441 name = tag.getAttribute("id");
442 } else {
443 beanNumber++;
444 }
445
446 return new BeanDefinitionHolder(bean.getBeanDefinition(), name);
447 }
448
449
450
451
452
453
454
455
456
457 protected Object parseCustomBean(Element tag, BeanDefinitionBuilder parent, ParserContext parserContext) {
458 BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(tag, parent.getBeanDefinition());
459
460 String name = beanDefinition.getParentName() + "$Customchild" + beanNumber;
461 if (tag.getAttribute("id") != null && !StringUtils.isEmpty(tag.getAttribute("id"))) {
462 name = tag.getAttribute("id");
463 } else {
464 beanNumber++;
465 }
466
467 return new BeanDefinitionHolder(beanDefinition, name);
468 }
469
470
471
472
473
474
475
476
477
478
479 protected ManagedList parseList(ArrayList<Element> grandChildren, Element child, BeanDefinitionBuilder parent,
480 ParserContext parserContext) {
481 ArrayList<Object> listItems = new ArrayList<Object>();
482
483 for (int i = 0; i < grandChildren.size(); i++) {
484 Element grandChild = grandChildren.get(i);
485
486 if (grandChild.getTagName().compareTo("value") == 0) {
487 listItems.add(grandChild.getTextContent());
488 } else {
489 listItems.add(parseBean(grandChild, parent, parserContext));
490 }
491 }
492
493 String merge = child.getAttribute("merge");
494
495 ManagedList beans = new ManagedList(listItems.size());
496 beans.addAll(listItems);
497
498 if (merge != null) {
499 beans.setMergeEnabled(Boolean.valueOf(merge));
500 }
501
502 return beans;
503 }
504
505
506
507
508
509
510
511
512
513
514 protected ManagedSet parseSet(ArrayList<Element> grandChildren, Element child, BeanDefinitionBuilder parent,
515 ParserContext parserContext) {
516 ManagedSet setItems = new ManagedSet();
517
518 for (int i = 0; i < grandChildren.size(); i++) {
519 Element grandChild = grandChildren.get(i);
520
521 if (child.getTagName().compareTo("value") == 0) {
522 setItems.add(grandChild.getTextContent());
523 } else {
524 setItems.add(parseBean(grandChild, parent, parserContext));
525 }
526 }
527
528 String merge = child.getAttribute("merge");
529 if (merge != null) {
530 setItems.setMergeEnabled(Boolean.valueOf(merge));
531 }
532
533 return setItems;
534 }
535
536
537
538
539
540
541
542
543
544
545 protected ManagedMap parseMap(ArrayList<Element> grandChildren, Element child, BeanDefinitionBuilder parent,
546 ParserContext parserContext) {
547 ManagedMap map = new ManagedMap();
548
549 String merge = child.getAttribute("merge");
550 if (merge != null) {
551 map.setMergeEnabled(Boolean.valueOf(merge));
552 }
553
554 for (int j = 0; j < grandChildren.size(); j++) {
555 Object key = findKey(grandChildren.get(j), parent, parserContext);
556 Object value = findValue(grandChildren.get(j), parent, parserContext);
557
558 map.put(key, value);
559 }
560
561 return map;
562 }
563
564 protected String nodesToString(NodeList nodeList) {
565 StringBuffer sb = new StringBuffer();
566
567 for (int i = 0; i < nodeList.getLength(); i++) {
568 Node node = nodeList.item(i);
569
570 sb.append(nodeToString(node));
571 }
572
573 return sb.toString();
574 }
575
576 protected String nodeToString(Node node) {
577 StringWriter stringOut = new StringWriter();
578
579 OutputFormat format = new OutputFormat(Method.XML, null, false);
580 format.setOmitXMLDeclaration(true);
581
582 XMLSerializer serial = new XMLSerializer(stringOut, format);
583
584 try {
585 serial.serialize(node);
586 } catch (IOException e) {
587 throw new RuntimeException(e);
588 }
589
590 return stringOut.toString();
591 }
592 }