View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.impl.xs;
22  
23  import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl;
24  import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
25  import com.sun.org.apache.xerces.internal.xs.StringList;
26  import com.sun.org.apache.xerces.internal.xs.XSAnnotation;
27  import com.sun.org.apache.xerces.internal.xs.XSConstants;
28  import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem;
29  import com.sun.org.apache.xerces.internal.xs.XSWildcard;
30  import com.sun.org.apache.xerces.internal.xs.XSObjectList;
31  
32  /**
33   * The XML representation for a wildcard declaration
34   * schema component is an <any> or <anyAttribute> element information item
35   *
36   * @xerces.internal
37   *
38   * @author Sandy Gao, IBM
39   * @author Rahul Srivastava, Sun Microsystems Inc.
40   *
41   * @version $Id: XSWildcardDecl.java,v 1.7 2010-11-01 04:39:55 joehw Exp $
42   */
43  public class XSWildcardDecl implements XSWildcard {
44  
45      public static final String ABSENT = null;
46  
47      // the type of wildcard: any, other, or list
48      public short fType = NSCONSTRAINT_ANY;
49      // the type of process contents: strict, lax, or skip
50      public short fProcessContents = PC_STRICT;
51      // the namespace list:
52      // for NSCONSTRAINT_LIST, it means one of the namespaces in the list
53      // for NSCONSTRAINT_NOT, it means not any of the namespaces in the list
54      public String[] fNamespaceList;
55  
56      // optional annotation
57      public XSObjectList fAnnotations = null;
58  
59      // I'm trying to implement the following constraint exactly as what the
60      // spec describes. Sometimes it seems redundant, and sometimes there seems
61      // to be much easier solutions. But it makes it easy to understand,
62      // easy to maintain, and easy to find a bug (either in the code, or in the
63      // spec). -SG
64      //
65      // NOTE: Schema spec only requires that ##other not(tNS,absent).
66      //       The way we store ##other is not(NS1,NS2,...,NSN), which covers
67      //       what's required by Schema, and allows future enhanced features.
68      //
69      // In the following in-line comments:
70      // - Bullet removed from w3c specification.
71      // + Bullet added as proposed by Sandy Gao, IBM.
72      // / Since we store ##other as not(NS1,NS2,...,NSN), we need to put some
73      //   comments on where we didn't follow the spec exactly.
74      // * When we really support not(NS1,NS2,...,NSN), we need to revisit these items.
75  
76      /**
77       * Validation Rule: Wildcard allows Namespace Name
78       */
79      public boolean allowNamespace(String namespace) {
80          // For a value which is either a namespace name or absent to be valid with respect to a wildcard constraint (the value of a {namespace constraint}) one of the following must be true:
81  
82          // 1 The constraint must be any.
83          if (fType == NSCONSTRAINT_ANY)
84              return true;
85  
86          // 2 All of the following must be true:
87          // 2.1 The constraint is a pair of not and a namespace name or absent ([Definition:]  call this the namespace test).
88          // 2.2 The value must not be identical to the namespace test.
89          // 2.3 The value must not be absent.
90          // / we store ##other as not(list), so our actual rule is
91          // / 2 The constraint is a pair of not and a set, and the value is not in such set.
92          if (fType == NSCONSTRAINT_NOT) {
93              boolean found = false;
94              int listNum = fNamespaceList.length;
95              for (int i = 0; i < listNum && !found; i++) {
96                  if (namespace == fNamespaceList[i])
97                      found = true;
98              }
99  
100             if (!found)
101                 return true;
102         }
103 
104         // 3 The constraint is a set, and the value is identical to one of the members of the set.
105         if (fType == NSCONSTRAINT_LIST) {
106             int listNum = fNamespaceList.length;
107             for (int i = 0; i < listNum; i++) {
108                 if (namespace == fNamespaceList[i])
109                     return true;
110             }
111         }
112 
113         // none of the above conditions applied, so return false.
114         return false;
115     }
116 
117     /**
118      *  Schema Component Constraint: Wildcard Subset
119      */
120     public boolean isSubsetOf(XSWildcardDecl superWildcard) {
121         // if the super is null (not expressible), return false
122         if (superWildcard == null)
123             return false;
124 
125         // For a namespace constraint (call it sub) to be an intensional subset of another
126         // namespace constraint (call it super) one of the following must be true:
127 
128         // 1 super must be any.
129         if (superWildcard.fType == NSCONSTRAINT_ANY) {
130             return true;
131         }
132 
133         // 2 All of the following must be true:
134         //   2.1 sub must be a pair of not and a namespace name or absent.
135         //   2.2 super must be a pair of not and the same value.
136         //   * we can't just compare whether the namespace are the same value
137         //     since we store other as not(list)
138         if (fType == NSCONSTRAINT_NOT) {
139             if (superWildcard.fType == NSCONSTRAINT_NOT &&
140                 fNamespaceList[0] == superWildcard.fNamespaceList[0]) {
141                 return true;
142             }
143         }
144 
145         // 3 All of the following must be true:
146         //   3.1 sub must be a set whose members are either namespace names or absent.
147         //   3.2 One of the following must be true:
148         //       3.2.1 super must be the same set or a superset thereof.
149         //       -3.2.2 super must be a pair of not and a namespace name or absent and
150         //              that value must not be in sub's set.
151         //       +3.2.2 super must be a pair of not and a namespace name or absent and
152         //              either that value or absent must not be in sub's set.
153         //       * since we store ##other as not(list), we acturally need to make sure
154         //         that none of the namespaces in super.list is in sub.list.
155         if (fType == NSCONSTRAINT_LIST) {
156             if (superWildcard.fType == NSCONSTRAINT_LIST &&
157                 subset2sets(fNamespaceList, superWildcard.fNamespaceList)) {
158                 return true;
159             }
160 
161             if (superWildcard.fType == NSCONSTRAINT_NOT &&
162                 !elementInSet(superWildcard.fNamespaceList[0], fNamespaceList) &&
163                 !elementInSet(ABSENT, fNamespaceList)) {
164                 return true;
165             }
166         }
167 
168         // none of the above conditions applied, so return false.
169         return false;
170 
171     } // isSubsetOf
172 
173     /**
174      * Check whether this wildcard has a weaker process contents than the super.
175      */
176     public boolean weakerProcessContents(XSWildcardDecl superWildcard) {
177         return fProcessContents == XSWildcardDecl.PC_LAX &&
178                superWildcard.fProcessContents == XSWildcardDecl.PC_STRICT ||
179                fProcessContents == XSWildcardDecl.PC_SKIP &&
180                superWildcard.fProcessContents != XSWildcardDecl.PC_SKIP;
181     }
182 
183     /**
184      * Schema Component Constraint: Attribute Wildcard Union
185      */
186     public XSWildcardDecl performUnionWith(XSWildcardDecl wildcard,
187                                            short processContents) {
188         // if the other wildcard is not expressible, the result is still not expressible
189         if (wildcard == null)
190             return null;
191 
192         // For a wildcard's {namespace constraint} value to be the intensional union of two
193         // other such values (call them O1 and O2): the appropriate case among the following
194         // must be true:
195 
196         XSWildcardDecl unionWildcard = new XSWildcardDecl();
197         unionWildcard.fProcessContents = processContents;
198 
199         // 1 If O1 and O2 are the same value, then that value must be the value.
200         if (areSame(wildcard)) {
201             unionWildcard.fType = fType;
202             unionWildcard.fNamespaceList = fNamespaceList;
203         }
204 
205         // 2 If either O1 or O2 is any, then any must be the value.
206         else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) {
207             unionWildcard.fType = NSCONSTRAINT_ANY;
208         }
209 
210         // 3 If both O1 and O2 are sets of (namespace names or absent), then the union of
211         //   those sets must be the value.
212         else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) {
213             unionWildcard.fType = NSCONSTRAINT_LIST;
214             unionWildcard.fNamespaceList = union2sets(fNamespaceList, wildcard.fNamespaceList);
215         }
216 
217         // -4 If the two are negations of different namespace names, then the intersection
218         //    is not expressible.
219         // +4 If the two are negations of different namespace names or absent, then
220         //    a pair of not and absent must be the value.
221         // * now we store ##other as not(list), the result should be
222         //   not(intersection of two lists).
223         else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) {
224             unionWildcard.fType = NSCONSTRAINT_NOT;
225             unionWildcard.fNamespaceList = new String[2];
226             unionWildcard.fNamespaceList[0] = ABSENT;
227             unionWildcard.fNamespaceList[1] = ABSENT;
228         }
229 
230         // 5 If either O1 or O2 is a pair of not and a namespace name and the other is a set of
231         //   (namespace names or absent), then The appropriate case among the following must be true:
232         //      -5.1 If the set includes the negated namespace name, then any must be the value.
233         //      -5.2 If the set does not include the negated namespace name, then whichever of O1 or O2
234         //           is a pair of not and a namespace name must be the value.
235         //    +5.1 If the negated value is a namespace name, then The appropriate case
236         //         among the following must be true:
237         //        +5.1.1 If the set includes both the namespace name and absent, then any
238         //               must be the value.
239         //        +5.1.2 If the set includes the namespace name but does not include
240         //               absent, then a pair of not and absent must be the value.
241         //        +5.1.3 If the set does not include the namespace name but includes
242         //               absent, then the union is not expressible.
243         //        +5.1.4 If the set does not include either the namespace name or absent,
244         //               then whichever of O1 or O2 is a pair of not and a namespace name must be
245         //               the value.
246         //    +5.2 If the negated value is absent, then The appropriate case among the
247         //         following must be true:
248         //        +5.2.1 If the set includes absent, then any must be the value.
249         //        +5.2.2 If the set does not include absent, then whichever of O1 or O2 is
250         //               a pair of not and a namespace name must be the value.
251         // * when we have not(list), the operation is just not(otherlist-list)
252         else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) ||
253                   ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) {
254             String[] other = null;
255             String[] list = null;
256 
257             if (fType == NSCONSTRAINT_NOT) {
258                 other = fNamespaceList;
259                 list = wildcard.fNamespaceList;
260             }
261             else {
262                 other = wildcard.fNamespaceList;
263                 list = fNamespaceList;
264             }
265 
266             boolean foundAbsent = elementInSet(ABSENT, list);
267 
268             if (other[0] != ABSENT) {
269                 boolean foundNS = elementInSet(other[0], list);
270                 if (foundNS && foundAbsent) {
271                     unionWildcard.fType = NSCONSTRAINT_ANY;
272                 } else if (foundNS && !foundAbsent) {
273                     unionWildcard.fType = NSCONSTRAINT_NOT;
274                     unionWildcard.fNamespaceList = new String[2];
275                     unionWildcard.fNamespaceList[0] = ABSENT;
276                     unionWildcard.fNamespaceList[1] = ABSENT;
277                 } else if (!foundNS && foundAbsent) {
278                     return null;
279                 } else { // !foundNS && !foundAbsent
280                     unionWildcard.fType = NSCONSTRAINT_NOT;
281                     unionWildcard.fNamespaceList = other;
282                 }
283             } else { // other[0] == ABSENT
284                 if (foundAbsent) {
285                     unionWildcard.fType = NSCONSTRAINT_ANY;
286                 } else { // !foundAbsent
287                     unionWildcard.fType = NSCONSTRAINT_NOT;
288                     unionWildcard.fNamespaceList = other;
289                 }
290             }
291         }
292 
293         return unionWildcard;
294 
295     } // performUnionWith
296 
297     /**
298      * Schema Component Constraint: Attribute Wildcard Intersection
299      */
300     public XSWildcardDecl performIntersectionWith(XSWildcardDecl wildcard,
301                                                   short processContents) {
302         // if the other wildcard is not expressible, the result is still not expressible
303         if (wildcard == null)
304             return null;
305 
306         // For a wildcard's {namespace constraint} value to be the intensional intersection of
307         // two other such values (call them O1 and O2): the appropriate case among the following
308         // must be true:
309 
310         XSWildcardDecl intersectWildcard = new XSWildcardDecl();
311         intersectWildcard.fProcessContents = processContents;
312 
313         // 1 If O1 and O2 are the same value, then that value must be the value.
314         if (areSame(wildcard)) {
315             intersectWildcard.fType = fType;
316             intersectWildcard.fNamespaceList = fNamespaceList;
317         }
318 
319         // 2 If either O1 or O2 is any, then the other must be the value.
320         else if ( (fType == NSCONSTRAINT_ANY) || (wildcard.fType == NSCONSTRAINT_ANY) ) {
321             // both cannot be ANY, if we have reached here.
322             XSWildcardDecl other = this;
323 
324             if (fType == NSCONSTRAINT_ANY)
325                 other = wildcard;
326 
327             intersectWildcard.fType = other.fType;
328             intersectWildcard.fNamespaceList = other.fNamespaceList;
329         }
330 
331         // -3 If either O1 or O2 is a pair of not and a namespace name and the other is a set of
332         //    (namespace names or absent), then that set, minus the negated namespace name if
333         //    it was in the set, must be the value.
334         // +3 If either O1 or O2 is a pair of not and a namespace name and the other
335         //    is a set of (namespace names or absent), then that set, minus the negated
336         //    namespace name if it was in the set, then minus absent if it was in the
337         //    set, must be the value.
338         // * when we have not(list), the operation is just list-otherlist
339         else if ( ((fType == NSCONSTRAINT_NOT) && (wildcard.fType == NSCONSTRAINT_LIST)) ||
340                   ((fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_NOT)) ) {
341             String[] list = null;
342             String[] other = null;
343 
344             if (fType == NSCONSTRAINT_NOT) {
345                 other = fNamespaceList;
346                 list = wildcard.fNamespaceList;
347             }
348             else {
349                 other = wildcard.fNamespaceList;
350                 list = fNamespaceList;
351             }
352 
353             int listSize = list.length;
354             String[] intersect = new String[listSize];
355             int newSize = 0;
356             for (int i = 0; i < listSize; i++) {
357                 if (list[i] != other[0] && list[i] != ABSENT)
358                     intersect[newSize++] = list[i];
359             }
360 
361             intersectWildcard.fType = NSCONSTRAINT_LIST;
362             intersectWildcard.fNamespaceList = new String[newSize];
363             System.arraycopy(intersect, 0, intersectWildcard.fNamespaceList, 0, newSize);
364         }
365 
366         // 4 If both O1 and O2 are sets of (namespace names or absent), then the intersection of those
367         //   sets must be the value.
368         else if ( (fType == NSCONSTRAINT_LIST) && (wildcard.fType == NSCONSTRAINT_LIST) ) {
369             intersectWildcard.fType = NSCONSTRAINT_LIST;
370             intersectWildcard.fNamespaceList = intersect2sets(fNamespaceList, wildcard.fNamespaceList);
371         }
372 
373         // -5 If the two are negations of different namespace names, then the intersection is not expressible.
374         // +5 If the two are negations of namespace names or absent, then The
375         //    appropriate case among the following must be true:
376         //    +5.1 If the two are negations of different namespace names, then the
377         //         intersection is not expressible.
378         //    +5.2 If one of the two is a pair of not and absent, the other must be
379         //         the value.
380         // * when we have not(list), the operation is just not(onelist+otherlist)
381         else if (fType == NSCONSTRAINT_NOT && wildcard.fType == NSCONSTRAINT_NOT) {
382             if (fNamespaceList[0] != ABSENT && wildcard.fNamespaceList[0] != ABSENT)
383                 return null;
384 
385             XSWildcardDecl other = this;
386             if (fNamespaceList[0] == ABSENT)
387                 other = wildcard;
388 
389             intersectWildcard.fType = other.fType;
390             intersectWildcard.fNamespaceList = other.fNamespaceList;
391         }
392 
393         return intersectWildcard;
394 
395     } // performIntersectionWith
396 
397     private boolean areSame(XSWildcardDecl wildcard) {
398         if (fType == wildcard.fType) {
399             // ##any, true
400             if (fType == NSCONSTRAINT_ANY)
401                 return true;
402 
403             // ##other, only check the negated value
404             // * when we support not(list), we need to check in the same way
405             //   as for NSCONSTRAINT_LIST.
406             if (fType == NSCONSTRAINT_NOT)
407                 return fNamespaceList[0] == wildcard.fNamespaceList[0];
408 
409             // ## list, must have the same length,
410             // and each item in one list must appear in the other one
411             // (we are assuming that there are no duplicate items in a list)
412             if (fNamespaceList.length == wildcard.fNamespaceList.length) {
413                 for (int i=0; i<fNamespaceList.length; i++) {
414                     if (!elementInSet(fNamespaceList[i], wildcard.fNamespaceList))
415                         return false;
416                 }
417                 return true;
418             }
419         }
420 
421         return false;
422     } // areSame
423 
424     String[] intersect2sets(String[] one, String[] theOther){
425         String[] result = new String[Math.min(one.length,theOther.length)];
426 
427         // simple implemention,
428         int count = 0;
429         for (int i=0; i<one.length; i++) {
430             if (elementInSet(one[i], theOther))
431                 result[count++] = one[i];
432         }
433 
434         String[] result2 = new String[count];
435         System.arraycopy(result, 0, result2, 0, count);
436 
437         return result2;
438     }
439 
440     String[] union2sets(String[] one, String[] theOther){
441         String[] result1 = new String[one.length];
442 
443         // simple implemention,
444         int count = 0;
445         for (int i=0; i<one.length; i++) {
446             if (!elementInSet(one[i], theOther))
447                 result1[count++] = one[i];
448         }
449 
450         String[] result2 = new String[count+theOther.length];
451         System.arraycopy(result1, 0, result2, 0, count);
452         System.arraycopy(theOther, 0, result2, count, theOther.length);
453 
454         return result2;
455     }
456 
457     boolean subset2sets(String[] subSet, String[] superSet){
458         for (int i=0; i<subSet.length; i++) {
459             if (!elementInSet(subSet[i], superSet))
460                 return false;
461         }
462 
463         return true;
464     }
465 
466     boolean elementInSet(String ele, String[] set){
467         boolean found = false;
468         for (int i=0; i<set.length && !found; i++) {
469             if (ele==set[i])
470                 found = true;
471         }
472 
473         return found;
474     }
475 
476     /**
477      * get the string description of this wildcard
478      */
479     private String fDescription = null;
480     public String toString() {
481         if (fDescription == null) {
482             StringBuffer buffer = new StringBuffer();
483             buffer.append("WC[");
484             switch (fType) {
485             case NSCONSTRAINT_ANY:
486                 buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDANY);
487                 break;
488             case NSCONSTRAINT_NOT:
489                 buffer.append(SchemaSymbols.ATTVAL_TWOPOUNDOTHER);
490                 buffer.append(":\"");
491                 if (fNamespaceList[0] != null)
492                     buffer.append(fNamespaceList[0]);
493                 buffer.append("\"");
494                 break;
495             case NSCONSTRAINT_LIST:
496                 if (fNamespaceList.length == 0)
497                     break;
498                 buffer.append("\"");
499                 if (fNamespaceList[0] != null)
500                     buffer.append(fNamespaceList[0]);
501                 buffer.append("\"");
502                 for (int i = 1; i < fNamespaceList.length; i++) {
503                     buffer.append(",\"");
504                     if (fNamespaceList[i] != null)
505                         buffer.append(fNamespaceList[i]);
506                     buffer.append("\"");
507                 }
508                 break;
509             }
510             buffer.append(']');
511             fDescription = buffer.toString();
512         }
513 
514         return fDescription;
515     }
516 
517     /**
518      * Get the type of the object, i.e ELEMENT_DECLARATION.
519      */
520     public short getType() {
521         return XSConstants.WILDCARD;
522     }
523 
524     /**
525      * The <code>name</code> of this <code>XSObject</code> depending on the
526      * <code>XSObject</code> type.
527      */
528     public String getName() {
529         return null;
530     }
531 
532     /**
533      * The namespace URI of this node, or <code>null</code> if it is
534      * unspecified.  defines how a namespace URI is attached to schema
535      * components.
536      */
537     public String getNamespace() {
538         return null;
539     }
540 
541     /**
542      * Namespace constraint: A constraint type: any, not, list.
543      */
544     public short getConstraintType() {
545         return fType;
546     }
547 
548     /**
549      * Namespace constraint. For <code>constraintType</code>
550      * LIST_NSCONSTRAINT, the list contains allowed namespaces. For
551      * <code>constraintType</code> NOT_NSCONSTRAINT, the list contains
552      * disallowed namespaces.
553      */
554     public StringList getNsConstraintList() {
555         return new StringListImpl(fNamespaceList, fNamespaceList == null ? 0 : fNamespaceList.length);
556     }
557 
558     /**
559      * {process contents} One of skip, lax or strict. Valid constants values
560      * are: PC_SKIP, PC_LAX, PC_STRICT.
561      */
562     public short getProcessContents() {
563         return fProcessContents;
564     }
565 
566     /**
567      * String valid of {process contents}. One of "skip", "lax" or "strict".
568      */
569     public String getProcessContentsAsString() {
570         switch (fProcessContents) {
571             case XSWildcardDecl.PC_SKIP: return "skip";
572             case XSWildcardDecl.PC_LAX: return "lax";
573             case XSWildcardDecl.PC_STRICT: return "strict";
574             default: return "invalid value";
575         }
576     }
577 
578     /**
579      * Optional. Annotation.
580      */
581     public XSAnnotation getAnnotation() {
582         return (fAnnotations != null) ? (XSAnnotation) fAnnotations.item(0) : null;
583     }
584 
585     /**
586      * Optional. Annotations.
587      */
588     public XSObjectList getAnnotations() {
589         return (fAnnotations != null) ? fAnnotations : XSObjectListImpl.EMPTY_LIST;
590     }
591 
592     /**
593      * @see org.apache.xerces.xs.XSObject#getNamespaceItem()
594      */
595     public XSNamespaceItem getNamespaceItem() {
596         return null;
597     }
598 
599 } // class XSWildcardDecl