1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl.xs;
23
24import com.sun.org.apache.xerces.internal.impl.xs.util.StringListImpl;
25import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
26import com.sun.org.apache.xerces.internal.xs.StringList;
27import com.sun.org.apache.xerces.internal.xs.XSAnnotation;
28import com.sun.org.apache.xerces.internal.xs.XSConstants;
29import com.sun.org.apache.xerces.internal.xs.XSNamespaceItem;
30import com.sun.org.apache.xerces.internal.xs.XSWildcard;
31import com.sun.org.apache.xerces.internal.xs.XSObjectList;
32
33/**
34 * The XML representation for a wildcard declaration
35 * schema component is an <any> or <anyAttribute> element information item
36 *
37 * @xerces.internal
38 *
39 * @author Sandy Gao, IBM
40 * @author Rahul Srivastava, Sun Microsystems Inc.
41 *
42 */
43public 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
600