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