1
2
3
4
5
6
7
8 package org.dom4j.rule;
9
10 import java.util.HashMap;
11 import java.util.Map;
12
13 import org.dom4j.Attribute;
14 import org.dom4j.Document;
15 import org.dom4j.Element;
16 import org.dom4j.Node;
17
18 /***
19 * <p>
20 * <code>Mode</code> manages a number of RuleSet instances for the mode in a
21 * stylesheet. It is responsible for finding the correct rule for a given DOM4J
22 * Node using the XSLT processing model uses the smallest possible RuleSet to
23 * reduce the number of Rule evaluations.
24 * </p>
25 *
26 * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
27 * @version $Revision: 1.9 $
28 */
29 public class Mode {
30 private RuleSet[] ruleSets = new RuleSet[Pattern.NUMBER_OF_TYPES];
31
32 /*** Map of exact (local) element names to RuleSet instances */
33 private Map elementNameRuleSets;
34
35 /*** Map of exact (local) attribute names to RuleSet instances */
36 private Map attributeNameRuleSets;
37
38 public Mode() {
39 }
40
41 /***
42 * Runs the actions associated with the given node
43 *
44 * @param node
45 * DOCUMENT ME!
46 *
47 * @throws Exception
48 * DOCUMENT ME!
49 */
50 public void fireRule(Node node) throws Exception {
51 if (node != null) {
52 Rule rule = getMatchingRule(node);
53
54 if (rule != null) {
55 Action action = rule.getAction();
56
57 if (action != null) {
58 action.run(node);
59 }
60 }
61 }
62 }
63
64 public void applyTemplates(Element element) throws Exception {
65 for (int i = 0, size = element.attributeCount(); i < size; i++) {
66 Attribute attribute = element.attribute(i);
67 fireRule(attribute);
68 }
69
70 for (int i = 0, size = element.nodeCount(); i < size; i++) {
71 Node node = element.node(i);
72 fireRule(node);
73 }
74 }
75
76 public void applyTemplates(Document document) throws Exception {
77 for (int i = 0, size = document.nodeCount(); i < size; i++) {
78 Node node = document.node(i);
79 fireRule(node);
80 }
81 }
82
83 public void addRule(Rule rule) {
84 int matchType = rule.getMatchType();
85 String name = rule.getMatchesNodeName();
86
87 if (name != null) {
88 if (matchType == Node.ELEMENT_NODE) {
89 elementNameRuleSets = addToNameMap(elementNameRuleSets, name,
90 rule);
91 } else if (matchType == Node.ATTRIBUTE_NODE) {
92 attributeNameRuleSets = addToNameMap(attributeNameRuleSets,
93 name, rule);
94 }
95 }
96
97 if (matchType >= Pattern.NUMBER_OF_TYPES) {
98 matchType = Pattern.ANY_NODE;
99 }
100
101 if (matchType == Pattern.ANY_NODE) {
102
103 for (int i = 1, size = ruleSets.length; i < size; i++) {
104 RuleSet ruleSet = ruleSets[i];
105
106 if (ruleSet != null) {
107 ruleSet.addRule(rule);
108 }
109 }
110 }
111
112 getRuleSet(matchType).addRule(rule);
113 }
114
115 public void removeRule(Rule rule) {
116 int matchType = rule.getMatchType();
117 String name = rule.getMatchesNodeName();
118
119 if (name != null) {
120 if (matchType == Node.ELEMENT_NODE) {
121 removeFromNameMap(elementNameRuleSets, name, rule);
122 } else if (matchType == Node.ATTRIBUTE_NODE) {
123 removeFromNameMap(attributeNameRuleSets, name, rule);
124 }
125 }
126
127 if (matchType >= Pattern.NUMBER_OF_TYPES) {
128 matchType = Pattern.ANY_NODE;
129 }
130
131 getRuleSet(matchType).removeRule(rule);
132
133 if (matchType != Pattern.ANY_NODE) {
134 getRuleSet(Pattern.ANY_NODE).removeRule(rule);
135 }
136 }
137
138 /***
139 * Performs an XSLT processing model match for the rule which matches the
140 * given Node the best.
141 *
142 * @param node
143 * is the DOM4J Node to match against
144 *
145 * @return the matching Rule or no rule if none matched
146 */
147 public Rule getMatchingRule(Node node) {
148 int matchType = node.getNodeType();
149
150 if (matchType == Node.ELEMENT_NODE) {
151 if (elementNameRuleSets != null) {
152 String name = node.getName();
153 RuleSet ruleSet = (RuleSet) elementNameRuleSets.get(name);
154
155 if (ruleSet != null) {
156 Rule answer = ruleSet.getMatchingRule(node);
157
158 if (answer != null) {
159 return answer;
160 }
161 }
162 }
163 } else if (matchType == Node.ATTRIBUTE_NODE) {
164 if (attributeNameRuleSets != null) {
165 String name = node.getName();
166 RuleSet ruleSet = (RuleSet) attributeNameRuleSets.get(name);
167
168 if (ruleSet != null) {
169 Rule answer = ruleSet.getMatchingRule(node);
170
171 if (answer != null) {
172 return answer;
173 }
174 }
175 }
176 }
177
178 if ((matchType < 0) || (matchType >= ruleSets.length)) {
179 matchType = Pattern.ANY_NODE;
180 }
181
182 Rule answer = null;
183 RuleSet ruleSet = ruleSets[matchType];
184
185 if (ruleSet != null) {
186
187 answer = ruleSet.getMatchingRule(node);
188 }
189
190 if ((answer == null) && (matchType != Pattern.ANY_NODE)) {
191
192 ruleSet = ruleSets[Pattern.ANY_NODE];
193
194 if (ruleSet != null) {
195 answer = ruleSet.getMatchingRule(node);
196 }
197 }
198
199 return answer;
200 }
201
202 /***
203 * DOCUMENT ME!
204 *
205 * @param matchType
206 * DOCUMENT ME!
207 *
208 * @return the RuleSet for the given matching type. This method will never
209 * return null, a new instance will be created.
210 */
211 protected RuleSet getRuleSet(int matchType) {
212 RuleSet ruleSet = ruleSets[matchType];
213
214 if (ruleSet == null) {
215 ruleSet = new RuleSet();
216 ruleSets[matchType] = ruleSet;
217
218
219 if (matchType != Pattern.ANY_NODE) {
220 RuleSet allRules = ruleSets[Pattern.ANY_NODE];
221
222 if (allRules != null) {
223 ruleSet.addAll(allRules);
224 }
225 }
226 }
227
228 return ruleSet;
229 }
230
231 /***
232 * Adds the Rule to a RuleSet for the given name.
233 *
234 * @param map
235 * DOCUMENT ME!
236 * @param name
237 * DOCUMENT ME!
238 * @param rule
239 * DOCUMENT ME!
240 *
241 * @return the Map (which will be created if the given map was null
242 */
243 protected Map addToNameMap(Map map, String name, Rule rule) {
244 if (map == null) {
245 map = new HashMap();
246 }
247
248 RuleSet ruleSet = (RuleSet) map.get(name);
249
250 if (ruleSet == null) {
251 ruleSet = new RuleSet();
252 map.put(name, ruleSet);
253 }
254
255 ruleSet.addRule(rule);
256
257 return map;
258 }
259
260 protected void removeFromNameMap(Map map, String name, Rule rule) {
261 if (map != null) {
262 RuleSet ruleSet = (RuleSet) map.get(name);
263
264 if (ruleSet != null) {
265 ruleSet.removeRule(rule);
266 }
267 }
268 }
269 }
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306