KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xerces > validators > common > AllContentModel


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57 package org.enhydra.apache.xerces.validators.common;
58
59 import java.util.Hashtable JavaDoc;
60
61 import org.enhydra.apache.xerces.framework.XMLContentSpec;
62 import org.enhydra.apache.xerces.utils.QName;
63 import org.enhydra.apache.xerces.validators.schema.SchemaGrammar;
64 import org.enhydra.apache.xerces.validators.schema.SubstitutionGroupComparator;
65
66 public class AllContentModel implements XMLContentModel {
67
68     private QName fAllElements[] = new QName[10];
69     private boolean fIsOptionalElement[] = new boolean[10];
70     private boolean fHasOptionalContent = false;
71     private boolean fIsMixed = false;
72
73     private int fNumElements = 0;
74     private int fNumRequired = 0;
75
76     private Hashtable JavaDoc fElementsHash;
77
78     /* this is the SubstitutionGroupComparator object */
79     private SubstitutionGroupComparator fComparator = null;
80
81     /** Set to true to debug content model validation. */
82     private static final boolean DEBUG_VALIDATE_CONTENT = false;
83
84     /**
85      *
86      */

87     public AllContentModel(boolean hasOptionalContent) {
88         fHasOptionalContent = hasOptionalContent;
89
90         if (DEBUG_VALIDATE_CONTENT) {
91             System.out.println("Entering AllContentModel#AllContentModel");
92             System.out.println(" this == "+this);
93             System.out.println(" optionalContent == "+hasOptionalContent);
94         }
95     }
96
97     public AllContentModel(boolean hasOptionalContent, boolean isMixed) {
98         this(hasOptionalContent);
99         fIsMixed = isMixed;
100
101         if (DEBUG_VALIDATE_CONTENT) {
102             System.out.println(" mixed == "+fIsMixed);
103         }
104     }
105
106     void addElement(QName newElement, boolean isOptional) {
107         if (DEBUG_VALIDATE_CONTENT) {
108             System.out.println("Entering AllContentModel#addElement");
109         }
110
111         // Need to resize arrays?
112
if (fNumElements >= fAllElements.length) {
113             QName newAllElements[] = new QName[2*fAllElements.length];
114             boolean newIsOptionalElements[] =
115                                       new boolean[2*fIsOptionalElement.length];
116
117             System.arraycopy(fAllElements, 0, newAllElements, 0,
118                              fAllElements.length);
119             System.arraycopy(fIsOptionalElement, 0, newIsOptionalElements, 0,
120                              fIsOptionalElement.length);
121
122             fAllElements = newAllElements;
123             fIsOptionalElement = newIsOptionalElements;
124         }
125
126         // Enter the new element into our array
127
fAllElements[fNumElements] = newElement;
128         fIsOptionalElement[fNumElements] = isOptional;
129
130         fNumElements++;
131
132         // Allows us to quickly determine whether all
133
// required items were seen during validation
134
if (!isOptional) {
135             fNumRequired++;
136         }
137
138         if (DEBUG_VALIDATE_CONTENT) {
139             showAllElements();
140             System.out.println("Leaving AllContentModel#addElement");
141         }
142     }
143
144     // Unique Particle Attribution
145
public void checkUniqueParticleAttribution(SchemaGrammar gram) throws Exception JavaDoc {
146         // rename back
147
for (int i = 0; i < fNumElements; i++)
148             fAllElements[i].uri = gram.getContentSpecOrgUri(fAllElements[i].uri);
149
150         // check whether there is conflict between any two leaves
151
for (int j = 0; j < fNumElements; j++) {
152             for (int k = j+1; k < fNumElements; k++) {
153                 ElementWildcard.conflict(XMLContentSpec.CONTENTSPECNODE_LEAF,
154                                          fAllElements[j].localpart,
155                                          fAllElements[j].uri,
156                                          XMLContentSpec.CONTENTSPECNODE_LEAF,
157                                          fAllElements[k].localpart,
158                                          fAllElements[k].uri,
159                                          fComparator);
160             }
161         }
162     }
163     // Unique Particle Attribution
164

165     /**
166      * Check that the specified content is valid according to this
167      * content model. This method can also be called to do 'what if'
168      * testing of content models just to see if they would be valid.
169      * <p>
170      * A value of -1 in the children array indicates a PCDATA node. All other
171      * indexes will be positive and represent child elements. The count can be
172      * zero, since some elements have the EMPTY content model and that must be
173      * confirmed.
174      *
175      * @param children The children of this element. Each integer is an index within
176      * the <code>StringPool</code> of the child element name. An index
177      * of -1 is used to indicate an occurrence of non-whitespace character
178      * data.
179      * @param offset Offset into the array where the children starts.
180      * @param length The number of entries in the <code>children</code> array.
181      *
182      * @return The value -1 if fully valid, else the 0 based index of the child
183      * that first failed. If the value returned is equal to the number
184      * of children, then the specified children are valid but additional
185      * content is required to reach a valid ending state.
186      *
187      * @exception Exception Thrown on error.
188      */

189     public int validateContent(QName children[], int offset, int length)
190         throws Exception JavaDoc {
191
192         if (DEBUG_VALIDATE_CONTENT)
193             System.out.println("Entering AllContentModel#validateContent");
194
195         // If <all> had minOccurs of zero and there are
196
// no children to validate, trivially validate
197
if (fHasOptionalContent && length == 0) {
198             if (DEBUG_VALIDATE_CONTENT) {
199                 System.out.println("Empty content");
200                 System.out.println("Leaving AllContentModel#validateContent");
201             }
202             return -1;
203         }
204
205         final int numElements = fNumElements;
206
207         if (fElementsHash == null)
208             createElementsHash();
209
210         // Check the elements seen for duplicated
211
// elements or elements that aren't permitted.
212
boolean elementSeen[] = new boolean[numElements];
213         int numRequiredSeen = 0;
214
215         for (int childIndex = 0; childIndex < length; childIndex++) {
216             QName currChild = children[offset + childIndex];
217
218             // Skip text node if in mixed mode.
219
if (fIsMixed && currChild.localpart == -1)
220                 continue;
221
222             Integer JavaDoc foundIdx = (Integer JavaDoc)fElementsHash.get(currChild);
223
224             // If this element was not found in the Hashtable of permitted
225
// elements or was seen already, indicate an error was found
226
// at the current index.
227
if (foundIdx == null) {
228                 if (DEBUG_VALIDATE_CONTENT) {
229                     System.out.println("Unexpected element seen - idx == "+
230                                        childIndex+" ("+currChild+")");
231                     System.out.println("Leaving AllContentModel#validateContent");
232                 }
233
234                 return childIndex;
235             }
236
237             int foundIdxVal = foundIdx.intValue();
238
239             // If this element was seen already, indicate an error was
240
// found at the duplicate index.
241
if (elementSeen[foundIdxVal]) {
242                 if (DEBUG_VALIDATE_CONTENT) {
243                     System.out.println("Duplicate element seen - idx == "+
244                                        childIndex+" ("+currChild+")");
245                     System.out.println("Leaving AllContentModel#validateContent");
246                 }
247
248                 return childIndex;
249             }
250
251             elementSeen[foundIdxVal] = true;
252
253             if (!fIsOptionalElement[foundIdxVal]) {
254                 numRequiredSeen++;
255             }
256         }
257
258         // Were all the required elements of the <all> encountered?
259
if (numRequiredSeen != fNumRequired) {
260             if (DEBUG_VALIDATE_CONTENT) {
261                 System.out.println("Required element missing");
262                 System.out.println("Leaving AllContentModel#validateContent");
263             }
264
265             return length;
266         }
267
268         if (DEBUG_VALIDATE_CONTENT) {
269             System.out.println("Successful validation");
270             System.out.println("Leaving AllContentModel#validateContent");
271         }
272
273         return -1;
274     }
275
276     /**
277      * This method is different from "validateContent" in that it will try to use
278      * the SubstitutionGroupComparator to match children against the content model.
279      * <p>
280      * A value of -1 in the children array indicates a PCDATA node. All other
281      * indexes will be positive and represent child elements. The count can be
282      * zero, since some elements have the EMPTY content model and that must be
283      * confirmed.
284      *
285      * @param children The children of this element. Each integer is an index within
286      * the <code>StringPool</code> of the child element name. An index
287      * of -1 is used to indicate an occurrence of non-whitespace character
288      * data.
289      * @param offset Offset into the array where the children starts.
290      * @param length The number of entries in the <code>children</code> array.
291      *
292      * @return The value -1 if fully valid, else the 0 based index of the child
293      * that first failed. If the value returned is equal to the number
294      * of children, then the specified children are valid but additional
295      * content is required to reach a valid ending state.
296      *
297      * @exception Exception Thrown on error.
298      */

299     public int validateContentSpecial(QName children[], int offset, int length)
300         throws Exception JavaDoc {
301
302         if (fComparator == null)
303             return validateContent(children, offset, length);
304
305         if (DEBUG_VALIDATE_CONTENT)
306             System.out.println("Entering AllContentModel#validateContentSpecial");
307
308         // If <all> had minOccurs of zero and there are
309
// no children to validate, trivially validate
310
if (fHasOptionalContent && length == 0) {
311             if (DEBUG_VALIDATE_CONTENT) {
312                 System.out.println("Empty content");
313                 System.out.println("Leaving AllContentModel#validateContentSpecial");
314             }
315             return -1;
316         }
317
318         final int numElements = fNumElements;
319
320         // Check the elements seen for duplicated
321
// elements or elements that aren't permitted.
322
boolean elementSeen[] = new boolean[numElements];
323         int numRequiredSeen = 0;
324
325         childLoop: for (int childIndex = 0; childIndex < length; childIndex++) {
326             QName currChild = children[offset + childIndex];
327
328             // Skip text node if in mixed mode.
329
if (fIsMixed && currChild.localpart == -1)
330                 continue;
331
332             int compareIdx;
333
334             for (compareIdx = 0; compareIdx < numElements; compareIdx++) {
335                 if (fComparator.isEquivalentTo(currChild,
336                                                fAllElements[compareIdx])) {
337                     // If this element was seen already, indicate an error was
338
// found at the duplicate index.
339
if (elementSeen[compareIdx]) {
340                         if (DEBUG_VALIDATE_CONTENT) {
341                             System.out.println("Duplicate element seen - idx == "+
342                                                childIndex+" ("+currChild+")");
343                             System.out.println("Leaving AllContentModel#validateContentSpecial");
344                         }
345
346                         return childIndex;
347                     }
348
349                     elementSeen[compareIdx] = true;
350
351                     if (!fIsOptionalElement[compareIdx]) {
352                         numRequiredSeen++;
353                     }
354
355                     // Found this element - go back for the next
356
continue childLoop;
357                 }
358             }
359
360             if (DEBUG_VALIDATE_CONTENT) {
361                 System.out.println("Unexpected element seen - idx == "+
362                                    childIndex+" ("+currChild+")");
363                 System.out.println("Leaving AllContentModel#validateContentSpecial");
364             }
365
366             // We didn't find the current element in the list of
367
// permitted elements, so report an error at this child
368
return childIndex;
369         }
370
371         // Were all the required elements of the <all> encountered?
372
if (numRequiredSeen != fNumRequired) {
373             if (DEBUG_VALIDATE_CONTENT) {
374                 System.out.println("Required element missing");
375                 System.out.println("Leaving AllContentModel#validateContentSpecial");
376             }
377
378             return length;
379         }
380
381         if (DEBUG_VALIDATE_CONTENT) {
382             System.out.println("Successful validation");
383             System.out.println("Leaving AllContentModel#validateContentSpecial");
384         }
385
386         return -1;
387     }
388
389     /**
390      * The setter method to pass in the SubstitutionGroupComparator.
391      *
392      * @param comparator a SubstitutionGroupComparator object.
393      * @return
394      * @exception
395      */

396     public void setSubstitutionGroupComparator(SubstitutionGroupComparator comparator) {
397         fComparator = comparator;
398     }
399
400     /**
401      * Returns information about which elements can be placed at a particular point
402      * in the passed element's content model.
403      * <p>
404      * Note that the incoming content model to test must be valid at least up to
405      * the insertion point. If not, then -1 will be returned and the info object
406      * will not have been filled in.
407      * <p>
408      * If, on return, the info.isValidEOC flag is set, then the 'insert after'
409      * element is a valid end of content. In other words, nothing needs to be
410      * inserted after it to make the parent element's content model valid.
411      *
412      * @param fullyValid Only return elements that can be inserted and still
413      * maintain the validity of subsequent elements past the
414      * insertion point (if any). If the insertion point is at
415      * the end, and this is true, then only elements that can
416      * be legal final states will be returned.
417      * @param info An object that contains the required input data for the method,
418      * and which will contain the output information if successful.
419      *
420      * @return The value -1 if fully valid, else the 0 based index of the child
421      * that first failed before the insertion point. If the value
422      * returned is equal to the number of children, then the specified
423      * children are valid but additional content is required to reach a
424      * valid ending state.
425      *
426      * @see InsertableElementsInfo
427      */

428     public int whatCanGoHere(boolean fullyValid,
429                              InsertableElementsInfo info) throws Exception JavaDoc {
430
431         if (DEBUG_VALIDATE_CONTENT)
432             System.out.println("Entering AllContentModel#whatCanGoHere");
433
434         // ????: How do we deal with "fHasOptionalContent"????
435

436         if (fElementsHash == null)
437             createElementsHash();
438
439         final int numElements = fNumElements;
440
441         // Check the elements seen for duplicated elements or
442
// elements that aren't permitted, up to insertion point.
443
boolean elementSeen[] = new boolean[numElements];
444
445         final int numChildren = info.curChildren.length;
446         final int insertAt = info.insertAt;
447         final QName curChildren[] = info.curChildren;
448
449         for (int childIndex = 0; childIndex < insertAt; childIndex++) {
450             QName currChild = curChildren[childIndex];
451
452             Integer JavaDoc foundIdx = (Integer JavaDoc)fElementsHash.get(currChild);
453
454             // If this element was not found in the Hashtable of permitted
455
// elements or was seen already, indicate an error was found
456
// at the current index.
457
if (foundIdx == null)
458                 return childIndex;
459
460             int foundIdxVal = foundIdx.intValue();
461
462             if (elementSeen[foundIdxVal])
463                 return childIndex;
464
465             elementSeen[foundIdxVal] = true;
466         }
467
468         info.canHoldPCData = fIsMixed;
469
470         final int resultsCount = numElements - insertAt;
471         info.resultsCount = resultsCount;
472
473         //
474
// If the outgoing arrays are too small or null, create new ones. These
475
// have to be at least the size of the results count.
476
//
477
if ((info.results == null) || (info.results.length < resultsCount))
478             info.results = new boolean[resultsCount];
479
480         if ((info.possibleChildren == null)
481         || (info.possibleChildren.length < resultsCount))
482         {
483             info.possibleChildren = new QName[resultsCount];
484
485             QName possibleChildren[] = info.possibleChildren;
486             final int possibleChildrenLen = info.possibleChildren.length;
487
488             for (int i = 0; i < possibleChildrenLen; i++) {
489                 possibleChildren[i] = new QName();
490             }
491         }
492
493         int possibleChildIdx = 0;
494
495         // Copy children that haven't been seen yet - they are
496
// the elements that may appear at the insertion point.
497
for (int elemIdx = 0; elemIdx < numElements; elemIdx++) {
498             if (!elementSeen[elemIdx]) {
499                 info.possibleChildren[possibleChildIdx].
500                            setValues(fAllElements[elemIdx]);
501                 info.results[possibleChildIdx] = true;
502                 possibleChildIdx++;
503             }
504         }
505
506         // EOC is valid only if all elements in ALL have been seen.
507
info.isValidEOC = (resultsCount == 0);
508
509         if (DEBUG_VALIDATE_CONTENT)
510             System.out.println("Leaving AllContentModel#whatCanGoHere");
511
512         if (resultsCount == 0)
513           return -1;
514
515         return info.childCount;
516         // ????: How do we deal with "fullyValidCheck"????
517
}
518
519     public ContentLeafNameTypeVector getContentLeafNameTypeVector() {
520         if (DEBUG_VALIDATE_CONTENT)
521             System.out.println("Entering AllContentModel#getContentLeafNameTypeVector");
522
523         if (DEBUG_VALIDATE_CONTENT)
524             System.out.println("Leaving AllContentModel#getContentLeafNameTypeVector");
525         // ???? HZ: What do I need to do here? ????
526
return null;
527     }
528
529     private void createElementsHash() {
530         int numElements = fNumElements;
531         fElementsHash = new Hashtable JavaDoc(numElements);
532
533         for (int elementIdx = 0; elementIdx < numElements; elementIdx++) {
534            // Won't do anything to handle duplicates here. That
535
// is left to Unique Particle Constraint checking.
536
fElementsHash.put(fAllElements[elementIdx],
537                              new Integer JavaDoc(elementIdx));
538         }
539     }
540
541     private void showAllElements() {
542         for (int elementIdx = 0;
543              elementIdx < fNumElements;
544              elementIdx++) {
545            System.out.print("fAllElements["+elementIdx+"] == " +
546                             fAllElements[elementIdx].toString());
547
548            if (fIsOptionalElement[elementIdx]) {
549                System.out.print(" (optional)");
550            }
551
552            System.out.println();
553         }
554     }
555 }
556
Popular Tags