1
2
3
4
5
6
7
8
9
10
11 package org.mule.config.spring.parsers.processors;
12
13 import java.util.Arrays;
14 import java.util.HashSet;
15 import java.util.Set;
16 import java.util.regex.Matcher;
17 import java.util.regex.Pattern;
18
19 import org.mule.config.spring.parsers.PreProcessor;
20 import org.mule.config.spring.parsers.assembly.configuration.PropertyConfiguration;
21 import org.mule.config.spring.util.SpringXMLUtils;
22 import org.w3c.dom.Attr;
23 import org.w3c.dom.Element;
24 import org.w3c.dom.NamedNodeMap;
25 import org.w3c.dom.Node;
26 import org.w3c.dom.NodeList;
27 import org.w3c.dom.TypeInfo;
28
29
30
31
32
33 public class CheckExclusiveAttributesAndChildren implements PreProcessor
34 {
35 private final static Pattern TYPE_REGEXP = Pattern.compile("\\{(.*)\\}(.*)");
36
37 private final Set<String> attributeNames;
38 private final Set<String> childrenNames;
39 private final Set<ChildType> childrenTypes;
40
41 private static class ChildType
42 {
43 String ns;
44 String name;
45
46 public ChildType(String ns, String name)
47 {
48 this.ns = ns;
49 this.name = name;
50 }
51
52 @Override
53 public String toString()
54 {
55 return "{" + ns + "}" + name;
56 }
57
58 }
59
60 public CheckExclusiveAttributesAndChildren(String[] attributeNames, String[] childrenNamesOrTypes)
61 {
62 this.attributeNames = new HashSet<String>(Arrays.asList(attributeNames));
63 this.childrenNames = new HashSet<String>();
64 this.childrenTypes = new HashSet<ChildType>();
65 parseChildrenNamesOrTypes(childrenNamesOrTypes);
66 }
67
68 private void parseChildrenNamesOrTypes(String[] childrenNamesOrTypes)
69 {
70 for (final String childrenNameOrType : childrenNamesOrTypes)
71 {
72 final Matcher matcher = TYPE_REGEXP.matcher(childrenNameOrType);
73 if (matcher.matches())
74 {
75 childrenTypes.add(new ChildType(matcher.group(1), matcher.group(2)));
76 }
77 else
78 {
79 childrenNames.add(childrenNameOrType);
80 }
81 }
82 }
83
84 public void preProcess(PropertyConfiguration config, Element element)
85 {
86 final NamedNodeMap attributes = element.getAttributes();
87 final int attributesCount = attributes.getLength();
88
89 for (int i = 0; i < attributesCount; i++)
90 {
91 final String attributeName = SpringXMLUtils.attributeName((Attr) attributes.item(i));
92
93 if (attributeNames.contains(attributeName))
94 {
95 ensureNoForbiddenChildren(element, attributeName);
96 }
97 }
98 }
99
100 private void ensureNoForbiddenChildren(Element element, final String attributeName)
101 {
102 final NodeList childNodes = element.getChildNodes();
103 final int childNodesCount = childNodes.getLength();
104 for (int j = 0; j < childNodesCount; j++)
105 {
106 checkChildNode(element, attributeName, childNodes.item(j));
107 }
108 }
109
110 private void checkChildNode(Element element, final String attributeName, final Node child)
111 {
112 if (child.getNodeType() == Node.ELEMENT_NODE)
113 {
114 checkChildElement(element, attributeName, (Element) child);
115 }
116 }
117
118 private void checkChildElement(Element element, final String attributeName, final Element child)
119 {
120 checkAttributeNameMatch(element, attributeName, child);
121
122 for (final ChildType childrenType : childrenTypes)
123 {
124 final TypeInfo typeInfo = (TypeInfo) child;
125
126 if (((childrenType.ns.equals(typeInfo.getTypeNamespace()) && childrenType.name.equals(typeInfo.getTypeName())))
127 || typeInfo.isDerivedFrom(childrenType.ns, childrenType.name, TypeInfo.DERIVATION_EXTENSION))
128 {
129
130 throw new CheckExclusiveAttributesAndChildrenException(
131 "Element " + SpringXMLUtils.elementToString(element) + " can't contain child of type "
132 + childrenType + " because it defines attribute " + attributeName);
133 }
134 }
135
136 }
137
138 private void checkAttributeNameMatch(Element element, final String attributeName, final Element child)
139 {
140 final String childElementName = child.getLocalName();
141
142 if (childrenNames.contains(childElementName))
143 {
144 throw new CheckExclusiveAttributesAndChildrenException("Element "
145 + SpringXMLUtils.elementToString(element)
146 + " can't contain child "
147 + childElementName
148 + " because it defines attribute "
149 + attributeName);
150 }
151 }
152
153 public static class CheckExclusiveAttributesAndChildrenException extends IllegalStateException
154 {
155 private static final long serialVersionUID = 8661524219979354246L;
156
157 public CheckExclusiveAttributesAndChildrenException(String message)
158 {
159 super(message);
160 }
161 }
162 }