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