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 | 0 | 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 | 0 | { |
48 | 0 | this.ns = ns; |
49 | 0 | this.name = name; |
50 | 0 | } |
51 | |
|
52 | |
@Override |
53 | |
public String toString() |
54 | |
{ |
55 | 0 | return "{" + ns + "}" + name; |
56 | |
} |
57 | |
|
58 | |
} |
59 | |
|
60 | |
public CheckExclusiveAttributesAndChildren(String[] attributeNames, String[] childrenNamesOrTypes) |
61 | 0 | { |
62 | 0 | this.attributeNames = new HashSet<String>(Arrays.asList(attributeNames)); |
63 | 0 | this.childrenNames = new HashSet<String>(); |
64 | 0 | this.childrenTypes = new HashSet<ChildType>(); |
65 | 0 | parseChildrenNamesOrTypes(childrenNamesOrTypes); |
66 | 0 | } |
67 | |
|
68 | |
private void parseChildrenNamesOrTypes(String[] childrenNamesOrTypes) |
69 | |
{ |
70 | 0 | for (final String childrenNameOrType : childrenNamesOrTypes) |
71 | |
{ |
72 | 0 | final Matcher matcher = TYPE_REGEXP.matcher(childrenNameOrType); |
73 | 0 | if (matcher.matches()) |
74 | |
{ |
75 | 0 | childrenTypes.add(new ChildType(matcher.group(1), matcher.group(2))); |
76 | |
} |
77 | |
else |
78 | |
{ |
79 | 0 | childrenNames.add(childrenNameOrType); |
80 | |
} |
81 | |
} |
82 | 0 | } |
83 | |
|
84 | |
public void preProcess(PropertyConfiguration config, Element element) |
85 | |
{ |
86 | 0 | final NamedNodeMap attributes = element.getAttributes(); |
87 | 0 | final int attributesCount = attributes.getLength(); |
88 | |
|
89 | 0 | for (int i = 0; i < attributesCount; i++) |
90 | |
{ |
91 | 0 | final String attributeName = SpringXMLUtils.attributeName((Attr) attributes.item(i)); |
92 | |
|
93 | 0 | if (attributeNames.contains(attributeName)) |
94 | |
{ |
95 | 0 | ensureNoForbiddenChildren(element, attributeName); |
96 | |
} |
97 | |
} |
98 | 0 | } |
99 | |
|
100 | |
private void ensureNoForbiddenChildren(Element element, final String attributeName) |
101 | |
{ |
102 | 0 | final NodeList childNodes = element.getChildNodes(); |
103 | 0 | final int childNodesCount = childNodes.getLength(); |
104 | 0 | for (int j = 0; j < childNodesCount; j++) |
105 | |
{ |
106 | 0 | checkChildNode(element, attributeName, childNodes.item(j)); |
107 | |
} |
108 | 0 | } |
109 | |
|
110 | |
private void checkChildNode(Element element, final String attributeName, final Node child) |
111 | |
{ |
112 | 0 | if (child.getNodeType() == Node.ELEMENT_NODE) |
113 | |
{ |
114 | 0 | checkChildElement(element, attributeName, (Element) child); |
115 | |
} |
116 | 0 | } |
117 | |
|
118 | |
private void checkChildElement(Element element, final String attributeName, final Element child) |
119 | |
{ |
120 | 0 | checkAttributeNameMatch(element, attributeName, child); |
121 | |
|
122 | 0 | for (final ChildType childrenType : childrenTypes) |
123 | |
{ |
124 | 0 | final TypeInfo typeInfo = (TypeInfo) child; |
125 | |
|
126 | 0 | if (((childrenType.ns.equals(typeInfo.getTypeNamespace()) && childrenType.name.equals(typeInfo.getTypeName()))) |
127 | |
|| typeInfo.isDerivedFrom(childrenType.ns, childrenType.name, TypeInfo.DERIVATION_EXTENSION)) |
128 | |
{ |
129 | |
|
130 | 0 | throw new CheckExclusiveAttributesAndChildrenException( |
131 | |
"Element " + SpringXMLUtils.elementToString(element) + " can't contain child of type " |
132 | |
+ childrenType + " because it defines attribute " + attributeName); |
133 | |
} |
134 | 0 | } |
135 | |
|
136 | 0 | } |
137 | |
|
138 | |
private void checkAttributeNameMatch(Element element, final String attributeName, final Element child) |
139 | |
{ |
140 | 0 | final String childElementName = child.getLocalName(); |
141 | |
|
142 | 0 | if (childrenNames.contains(childElementName)) |
143 | |
{ |
144 | 0 | throw new CheckExclusiveAttributesAndChildrenException("Element " |
145 | |
+ SpringXMLUtils.elementToString(element) |
146 | |
+ " can't contain child " |
147 | |
+ childElementName |
148 | |
+ " because it defines attribute " |
149 | |
+ attributeName); |
150 | |
} |
151 | 0 | } |
152 | |
|
153 | |
public static class CheckExclusiveAttributesAndChildrenException extends IllegalStateException |
154 | |
{ |
155 | |
private static final long serialVersionUID = 8661524219979354246L; |
156 | |
|
157 | |
public CheckExclusiveAttributesAndChildrenException(String message) |
158 | |
{ |
159 | 0 | super(message); |
160 | 0 | } |
161 | |
} |
162 | |
} |