KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > pde > internal > core > builders > ElementOccurenceChecker


1 /*******************************************************************************
2  * Copyright (c) 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.pde.internal.core.builders;
13
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16
17 import org.eclipse.pde.internal.core.ischema.ISchemaComplexType;
18 import org.eclipse.pde.internal.core.ischema.ISchemaCompositor;
19 import org.eclipse.pde.internal.core.ischema.ISchemaElement;
20 import org.eclipse.pde.internal.core.ischema.ISchemaObject;
21 import org.w3c.dom.Element JavaDoc;
22 import org.w3c.dom.Node JavaDoc;
23 import org.w3c.dom.NodeList JavaDoc;
24
25 /**
26  * XMLElementProposalComputer
27  *
28  */

29 public class ElementOccurenceChecker {
30
31     /**
32      * @param sElement
33      * @param element
34      * @return A set of elements that are first-level children of
35      * <code>element</code>, that violate max occurence rules defined by
36      * <code>sElement</code>.
37      */

38     public static HashSet JavaDoc findMaxOccurenceViolations(ISchemaElement sElement,
39             Element element) {
40         // Calculate the number of occurrences of each XML tag name
41
// in the node's direct children
42
HashMap JavaDoc tagNameMap = countXMLChildrenByTagName(element);
43         return processChildrenMax(sElement, tagNameMap, element);
44     }
45
46     /**
47      * @param sElement
48      * @param element
49      * @return A set of elements that are first-level children of
50      * <code>element</code>, that violate min occurence rules defined by
51      * <code>sElement</code>.
52      */

53     public static HashSet JavaDoc findMinOccurenceViolations(ISchemaElement sElement,
54             Element element) {
55         // Calculate the number of occurrences of each XML tag name
56
// in the node's direct children
57
HashMap JavaDoc tagNameMap = countXMLChildrenByTagName(element);
58         return processChildrenMin(sElement, tagNameMap);
59     }
60     
61     /**
62      * @param element
63      * @return A hash containing singleton entries of node's children mapped
64      * against the number of occurrences found
65      * Key is children's XML tag name
66      * Value is number of occurrences found amongst siblings
67      */

68     private static HashMap JavaDoc countXMLChildrenByTagName(Element element) {
69         NodeList JavaDoc children = element.getChildNodes();
70         HashMap JavaDoc tagNameMap = new HashMap JavaDoc();
71         
72         for (int i = 0; i < children.getLength(); i++) {
73             Node JavaDoc child = children.item(i);
74             if (child.getNodeType() == Node.ELEMENT_NODE) {
75                 String JavaDoc key = child.getNodeName();
76                 if (tagNameMap.containsKey(key)) {
77                     int value = ((Integer JavaDoc)tagNameMap.get(key)).intValue();
78                     value++;
79                     tagNameMap.put(key, new Integer JavaDoc(value));
80                 } else {
81                     tagNameMap.put(key, new Integer JavaDoc(1));
82                 }
83             }
84         }
85         
86         return tagNameMap;
87     }
88     
89     /**
90      * @param sElement
91      * @param tagNameMap
92      * @return
93      */

94     private static HashSet JavaDoc processChildrenMax(ISchemaElement sElement,
95             HashMap JavaDoc tagNameMap, Element element) {
96         
97         HashSet JavaDoc elementSet = new HashSet JavaDoc();
98         // Get this element's compositor
99
ISchemaCompositor compositor =
100             ((ISchemaComplexType)sElement.getType()).getCompositor();
101         // Track multiplicity
102
int multiplicityTracker = 1;
103         // Process the compositor
104
processCompositorMax(compositor,
105                 elementSet, tagNameMap, multiplicityTracker, element);
106         return elementSet;
107     }
108
109     /**
110      * @param sElement
111      * @param tagNameMap
112      * @return
113      */

114     private static HashSet JavaDoc processChildrenMin(ISchemaElement sElement,
115             HashMap JavaDoc tagNameMap) {
116         
117         HashSet JavaDoc elementSet = new HashSet JavaDoc();
118         // Get this element's compositor
119
ISchemaCompositor compositor =
120             ((ISchemaComplexType)sElement.getType()).getCompositor();
121         // Track multiplicity
122
int multiplicityTracker = 1;
123         // Process the compositor
124
processCompositorMin(compositor,
125                 elementSet, tagNameMap, multiplicityTracker);
126         return elementSet;
127     }
128
129     /**
130      * @param compositor
131      * @param proposalList
132      * @param siblings
133      * @param multiplicityTracker
134      */

135     private static void processCompositorMin(
136             ISchemaCompositor compositor, HashSet JavaDoc elementSet,
137             HashMap JavaDoc siblings, int multiplicityTracker) {
138         // Compositor can be null only in cases where we had a schema complex
139
// type but that complex type was complex because it had attributes
140
// rather than element children
141
// All we care about is choices and sequences (Alls and groups not
142
// supported)
143
if (compositor == null) {
144             return;
145         } else if (compositor.getKind() == ISchemaCompositor.CHOICE) {
146             processChoiceMin(compositor, elementSet, siblings,
147                     multiplicityTracker);
148         } else if (compositor.getKind() == ISchemaCompositor.SEQUENCE) {
149             processSequenceMin(compositor, elementSet, siblings,
150                     multiplicityTracker);
151         }
152     }
153     
154     
155     /**
156      * @param compositor
157      * @param proposalList
158      * @param siblings
159      * @param multiplicityTracker
160      */

161     private static void processCompositorMax(
162             ISchemaCompositor compositor, HashSet JavaDoc elementSet,
163             HashMap JavaDoc siblings, int multiplicityTracker, Element element) {
164         // Compositor can be null only in cases where we had a schema complex
165
// type but that complex type was complex because it had attributes
166
// rather than element children
167
// All we care about is choices and sequences (Alls and groups not
168
// supported)
169
if (compositor == null) {
170             return;
171         } else if (compositor.getKind() == ISchemaCompositor.CHOICE) {
172             processChoiceMax(compositor, elementSet, siblings,
173                     multiplicityTracker, element);
174         } else if (compositor.getKind() == ISchemaCompositor.SEQUENCE) {
175             processSequenceMax(compositor, elementSet, siblings,
176                     multiplicityTracker, element);
177         }
178     }
179
180     /**
181      * @param compositor
182      * @param elementSet
183      * @param siblings
184      * @param multiplicityTracker
185      */

186     private static void processSequenceMin(
187             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
188             int multiplicityTracker) {
189
190         ISchemaObject[] schemaObject = compositor.getChildren();
191         // Unbounded min occurs are represented by the maximum integer value
192
if (multiplicityTracker < Integer.MAX_VALUE) {
193             // Multiply the min occurs amount to the overall multiplicity
194
multiplicityTracker = compositor.getMinOccurs() * multiplicityTracker;
195         }
196         // Process the compositors children
197
for (int i = 0; i < compositor.getChildCount(); i++) {
198             processObjectMin(schemaObject[i], elementSet,
199                     siblings, multiplicityTracker);
200         }
201     }
202     
203     /**
204      * @param compositor
205      * @param elementSet
206      * @param siblings
207      * @param multiplicityTracker
208      */

209     private static void processSequenceMax(
210             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
211             int multiplicityTracker, Element element) {
212
213         ISchemaObject[] schemaObject = compositor.getChildren();
214         // Unbounded max occurs are represented by the maximum integer value
215
if (multiplicityTracker < Integer.MAX_VALUE) {
216             // Multiply the max occurs amount to the overall multiplicity
217
multiplicityTracker = compositor.getMaxOccurs() * multiplicityTracker;
218         }
219         // Process the compositors children
220
for (int i = 0; i < compositor.getChildCount(); i++) {
221             processObjectMax(schemaObject[i], elementSet,
222                     siblings, multiplicityTracker, element);
223         }
224     }
225
226     /**
227      * @param compositor
228      * @param elementSet
229      * @param siblings
230      * @param multiplicityTracker
231      */

232     private static void processChoiceMin(
233             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
234             int multiplicityTracker) {
235
236         // Unbounded min occurs are represented by the maximum integer value
237
if (multiplicityTracker < Integer.MAX_VALUE) {
238             // Multiply the min occurs amount to the overall multiplicity
239
multiplicityTracker = compositor.getMinOccurs() * multiplicityTracker;
240         }
241         adjustChoiceMinSiblings(compositor, siblings);
242         
243         ISchemaObject[] schemaObject = compositor.getChildren();
244         // Process the compositors children
245
for (int i = 0; i < compositor.getChildCount(); i++) {
246             processObjectMin(schemaObject[i], elementSet,
247                     siblings, multiplicityTracker);
248         }
249     }
250     
251     /**
252      * @param compositor
253      * @param elementSet
254      * @param siblings
255      * @param multiplicityTracker
256      */

257     private static void processChoiceMax(
258             ISchemaCompositor compositor, HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
259             int multiplicityTracker, Element element) {
260
261         // Unbounded max occurs are represented by the maximum integer value
262
if (multiplicityTracker < Integer.MAX_VALUE) {
263             // Multiply the max occurs amount to the overall multiplicity
264
multiplicityTracker = compositor.getMaxOccurs() * multiplicityTracker;
265         }
266         adjustChoiceMaxSiblings(compositor, siblings);
267         
268         ISchemaObject[] schemaObject = compositor.getChildren();
269         // Process the compositors children
270
for (int i = 0; i < compositor.getChildCount(); i++) {
271             processObjectMax(schemaObject[i], elementSet,
272                     siblings, multiplicityTracker, element);
273         }
274     }
275
276     /**
277      * @param compositor
278      * @param siblings
279      */

280     private static void adjustChoiceMaxSiblings(ISchemaCompositor compositor,
281             HashMap JavaDoc siblings) {
282
283         if (isSimpleChoice(compositor)) {
284             // Supported
285
// Update all child element occurrences of the choice compositor
286
// to the number of occurences found
287
// Each choice occurence counts as one occurence for all child elements
288
// of that choice
289
int childElementCount =
290                 countChoiceElementChildren(compositor, siblings);
291             updateChoiceElementChildren(compositor, siblings, childElementCount);
292         } else {
293             // Not supported
294
// IMPORTANT: Any child of choice that is not an element (e.g.
295
// sequence, choice) is not supported, in future could recursively
296
// caculate, but time vs benefit is not worth it
297
// Remove all elements nested in compositors from validation check
298
// by setting their occurrences to integer MIN
299
updateChoiceElementChildren(compositor, siblings, Integer.MIN_VALUE);
300         }
301     }
302     
303     /**
304      * @param compositor
305      * @return
306      */

307     private static boolean isSimpleChoice(ISchemaCompositor compositor) {
308         ISchemaObject[] schemaObject = compositor.getChildren();
309         // Simple choice compositors only have elements as children
310
// Complex choice compositors have one or more choice or sequence
311
// compositors as children
312
for (int i = 0; i < compositor.getChildCount(); i++) {
313             if (schemaObject[i] instanceof ISchemaCompositor) {
314                 return false;
315             }
316         }
317         return true;
318     }
319     
320     /**
321      * @param compositor
322      * @param siblings
323      */

324     private static void adjustChoiceMinSiblings(ISchemaCompositor compositor,
325             HashMap JavaDoc siblings) {
326
327         if (isSimpleChoice(compositor)) {
328             // Supported
329
// Update all child element occurrences of the choice compositor
330
// to the number of occurences found
331
// Each choice occurence counts as one occurence for all child elements
332
// of that choice
333
int childElementCount =
334                 countChoiceElementChildren(compositor, siblings);
335             updateChoiceElementChildren(compositor, siblings, childElementCount);
336         } else {
337             // Not supported
338
// IMPORTANT: Any child of choice that is not an element (e.g.
339
// sequence, choice) is not supported, in future could recursively
340
// caculate, but time vs benefit is not worth it
341
// Remove all elements nested in compositors from validation check
342
// by setting their occurrences to integer MAX
343
updateChoiceElementChildren(compositor, siblings, Integer.MAX_VALUE);
344         }
345     }
346     
347     /**
348      * @param compositor
349      * @param siblings
350      * @return
351      */

352     private static int countChoiceElementChildren(ISchemaCompositor compositor,
353             HashMap JavaDoc siblings) {
354         ISchemaObject[] schemaObject = compositor.getChildren();
355         // Count the number of child element occurrences of the choice
356
// Compositor
357
int childElementCount = 0;
358         for (int i = 0; i < compositor.getChildCount(); i++) {
359             if (schemaObject[i] instanceof ISchemaElement) {
360                 String JavaDoc name = schemaObject[i].getName();
361                 if (siblings.containsKey(name)) {
362                     int occurences = ((Integer JavaDoc)siblings.get(name)).intValue();
363                     if (childElementCount < Integer.MAX_VALUE) {
364                         childElementCount = childElementCount + occurences;
365                     }
366                 }
367             }
368         }
369         return childElementCount;
370     }
371     
372     /**
373      * @param compositor
374      * @param siblings
375      * @param childElementCount
376      */

377     private static void updateChoiceElementChildren(ISchemaCompositor compositor,
378             HashMap JavaDoc siblings, int childElementCount) {
379         ISchemaObject[] schemaObject = compositor.getChildren();
380         for (int i = 0; i < compositor.getChildCount(); i++) {
381             if (schemaObject[i] instanceof ISchemaElement) {
382                 String JavaDoc name = schemaObject[i].getName();
383                 siblings.put(name, new Integer JavaDoc(childElementCount));
384             } else if (schemaObject[i] instanceof ISchemaCompositor) {
385                 updateChoiceElementChildren((ISchemaCompositor)schemaObject[i],
386                         siblings, childElementCount);
387             }
388         }
389     }
390     
391     /**
392      * @param schemaObject
393      * @param proposalList
394      * @param siblings
395      * @param multiplicityTracker
396      */

397     private static void processObjectMax(ISchemaObject schemaObject,
398             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
399             int multiplicityTracker, Element element) {
400         if (schemaObject instanceof ISchemaElement) {
401             ISchemaElement schemaElement = (ISchemaElement)schemaObject;
402             Element childElement = findChildElement(element, schemaElement.getName());
403             if (childElement != null) {
404                 processElementMax(schemaElement, elementSet,
405                     siblings, multiplicityTracker, childElement);
406             }
407         } else if (schemaObject instanceof ISchemaCompositor) {
408             ISchemaCompositor sCompositor = (ISchemaCompositor)schemaObject;
409             processCompositorMax(sCompositor, elementSet,
410                     siblings, multiplicityTracker, element);
411         }
412     }
413
414     /**
415      * @param schemaObject
416      * @param proposalList
417      * @param siblings
418      * @param multiplicityTracker
419      */

420     private static void processObjectMin(ISchemaObject schemaObject,
421             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
422             int multiplicityTracker) {
423         if (schemaObject instanceof ISchemaElement) {
424             ISchemaElement schemaElement = (ISchemaElement)schemaObject;
425             processElementMin(schemaElement, elementSet,
426                     siblings, multiplicityTracker);
427         } else if (schemaObject instanceof ISchemaCompositor) {
428             ISchemaCompositor sCompositor = (ISchemaCompositor)schemaObject;
429             processCompositorMin(sCompositor, elementSet,
430                     siblings, multiplicityTracker);
431         }
432     }
433     
434     /**
435      * @param schemaElement
436      * @param proposalList
437      * @param siblings
438      * @param multiplicityTracker
439      */

440     private static void processElementMax(ISchemaElement schemaElement,
441             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
442             int multiplicityTracker, Element element) {
443
444         int occurrences = 0;
445         String JavaDoc name = schemaElement.getName();
446         // Determine the number of occurrences found of this element
447
if (siblings.containsKey(name)) {
448             occurrences = ((Integer JavaDoc) siblings.get(schemaElement.getName()))
449                     .intValue();
450         }
451         // Determine if the elements max occurrences is respected
452
if (multiplicityTracker < Integer.MAX_VALUE) {
453             multiplicityTracker = schemaElement.getMaxOccurs() * multiplicityTracker;
454         }
455         // If a given element occurs more than the tracked max occurs, add
456
// it to the list
457
// Note: This is a simple calculation that does not address all complex
458
// XML Schema multiplity rules. For instance, multiple layers of
459
// choices and sequences compositors coupled with varying siblings
460
// elements require a regex processor
461
// For the PDE space this is not required as extension point schemas
462
// are always very simple
463
if (occurrences > multiplicityTracker) {
464             elementSet.add(new ElementOccurrenceResult(element, schemaElement,
465                     occurrences, multiplicityTracker));
466         }
467     }
468
469     /**
470      * @param schemaElement
471      * @param proposalList
472      * @param siblings
473      * @param multiplicityTracker
474      */

475     private static void processElementMin(ISchemaElement schemaElement,
476             HashSet JavaDoc elementSet, HashMap JavaDoc siblings,
477             int multiplicityTracker) {
478
479         int occurrences = 0;
480         String JavaDoc name = schemaElement.getName();
481         // Determine the number of occurrences found of this element
482
if (siblings.containsKey(name)) {
483             occurrences = ((Integer JavaDoc) siblings.get(schemaElement.getName()))
484                     .intValue();
485         }
486         // Determine if the elements min occurrences is respected
487
if (multiplicityTracker < Integer.MAX_VALUE) {
488             multiplicityTracker = schemaElement.getMinOccurs() * multiplicityTracker;
489         }
490         // If a given element occurs les than the tracked min occurs, add
491
// it to the list
492
// Note: This is a simple calculation that does not address all complex
493
// XML Schema multiplity rules. For instance, multiple layers of
494
// choices and sequences compositors coupled with varying siblings
495
// elements require a regex processor
496
// For the PDE space this is not required as extension point schemas
497
// are always very simple
498
if (occurrences < multiplicityTracker) {
499             elementSet.add(new ElementOccurrenceResult(null, schemaElement,
500                     occurrences, multiplicityTracker));
501         }
502     }
503     
504     /**
505      * @param element
506      * @param name
507      * @return
508      */

509     private static Element findChildElement(Element element, String JavaDoc name) {
510         NodeList JavaDoc children = element.getChildNodes();
511         Element match = null;
512         for (int i = 0; i < children.getLength(); i++) {
513             Node JavaDoc child = children.item(i);
514             if (child.getNodeType() == Node.ELEMENT_NODE) {
515                 String JavaDoc key = child.getNodeName();
516                 if (key.equals(name)) {
517                     // Normally we would return as soon as an matching element
518
// is found; however, we want to return the last
519
// occurrence at the expense of performance in order to
520
// flag the last element exceeding allowed maximum
521
// occurrence
522
match = (Element)child;
523                 }
524             }
525         }
526         return match;
527     }
528     
529 }
530
Popular Tags