1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-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 java.util.Collections;
  24 import java.util.Comparator;
  25 import java.util.Vector;
  26 
  27 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  28 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  29 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
  30 import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext;
  31 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  32 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
  33 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator;
  34 import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator;
  35 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
  36 import com.sun.org.apache.xerces.internal.util.SymbolHash;
  37 import com.sun.org.apache.xerces.internal.xs.XSConstants;
  38 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  39 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  40 
  41 /**
  42  * Constaints shared by traversers and validator
  43  *
  44  * @xerces.internal
  45  *
  46  * @author Sandy Gao, IBM
  47  *
  48  */
  49 public class XSConstraints {
  50 
  51     // IHR: Visited on 2006-11-17
  52     // Added a boolean return value to particleValidRestriction (it was a void function)
  53     // to help the checkRecurseLax to know when expansion has happened and no order is required
  54     // (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com)
  55 
  56     static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1;
  57     static final XSSimpleType STRING_TYPE = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING);
  58 
  59     private static XSParticleDecl fEmptyParticle = null;
  60     public static XSParticleDecl getEmptySequence() {
  61         if (fEmptyParticle == null) {
  62             XSModelGroupImpl group = new XSModelGroupImpl();
  63             group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE;
  64             group.fParticleCount = 0;
  65             group.fParticles = null;
  66             group.fAnnotations = XSObjectListImpl.EMPTY_LIST;
  67             XSParticleDecl particle = new XSParticleDecl();
  68             particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
  69             particle.fValue = group;
  70             particle.fAnnotations = XSObjectListImpl.EMPTY_LIST;
  71             fEmptyParticle = particle;
  72         }
  73         return fEmptyParticle;
  74     }
  75 
  76     private static final Comparator ELEMENT_PARTICLE_COMPARATOR = new Comparator() {
  77 
  78         public int compare(Object o1, Object o2) {
  79             XSParticleDecl pDecl1 = (XSParticleDecl) o1;
  80             XSParticleDecl pDecl2 = (XSParticleDecl) o2;
  81             XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue;
  82             XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue;
  83 
  84             String namespace1 = decl1.getNamespace();
  85             String namespace2 = decl2.getNamespace();
  86             String name1 = decl1.getName();
  87             String name2 = decl2.getName();
  88 
  89             boolean sameNamespace = (namespace1 == namespace2);
  90             int namespaceComparison = 0;
  91 
  92             if (!sameNamespace) {
  93                 if (namespace1 != null) {
  94                     if (namespace2 != null){
  95                         namespaceComparison = namespace1.compareTo(namespace2);
  96                     }
  97                     else {
  98                         namespaceComparison = 1;
  99                     }
 100                 }
 101                 else {
 102                     namespaceComparison = -1;
 103                 }
 104             }
 105             //This assumes that the names are never null.
 106             return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2);
 107         }
 108     };
 109 
 110     /**
 111      * check whether derived is valid derived from base, given a subset
 112      * of {restriction, extension}.B
 113      */
 114     public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) {
 115         // if derived is anyType, then it's valid only if base is anyType too
 116         if (derived == SchemaGrammar.fAnyType)
 117             return derived == base;
 118         // if derived is anySimpleType, then it's valid only if the base
 119         // is ur-type
 120         if (derived == SchemaGrammar.fAnySimpleType) {
 121             return (base == SchemaGrammar.fAnyType ||
 122                     base == SchemaGrammar.fAnySimpleType);
 123         }
 124 
 125         // if derived is simple type
 126         if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 127             // if base is complex type
 128             if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 129                 // if base is anyType, change base to anySimpleType,
 130                 // otherwise, not valid
 131                 if (base == SchemaGrammar.fAnyType)
 132                     base = SchemaGrammar.fAnySimpleType;
 133                 else
 134                     return false;
 135             }
 136             return checkSimpleDerivation((XSSimpleType)derived,
 137                     (XSSimpleType)base, block);
 138         }
 139         else {
 140             return checkComplexDerivation((XSComplexTypeDecl)derived, base, block);
 141         }
 142     }
 143 
 144     /**
 145      * check whether simple type derived is valid derived from base,
 146      * given a subset of {restriction, extension}.
 147      */
 148     public static boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) {
 149         // if derived is anySimpleType, then it's valid only if the base
 150         // is ur-type
 151         if (derived == SchemaGrammar.fAnySimpleType) {
 152             return (base == SchemaGrammar.fAnyType ||
 153                     base == SchemaGrammar.fAnySimpleType);
 154         }
 155 
 156         // if base is complex type
 157         if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 158             // if base is anyType, change base to anySimpleType,
 159             // otherwise, not valid
 160             if (base == SchemaGrammar.fAnyType)
 161                 base = SchemaGrammar.fAnySimpleType;
 162             else
 163                 return false;
 164         }
 165         return checkSimpleDerivation((XSSimpleType)derived,
 166                 (XSSimpleType)base, block);
 167     }
 168 
 169     /**
 170      * check whether complex type derived is valid derived from base,
 171      * given a subset of {restriction, extension}.
 172      */
 173     public static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) {
 174         // if derived is anyType, then it's valid only if base is anyType too
 175         if (derived == SchemaGrammar.fAnyType)
 176             return derived == base;
 177         return checkComplexDerivation((XSComplexTypeDecl)derived, base, block);
 178     }
 179 
 180     /**
 181      * Note: this will be a private method, and it assumes that derived is not
 182      *       anySimpleType, and base is not anyType. Another method will be
 183      *       introduced for public use, which will call this method.
 184      */
 185     private static boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) {
 186         // 1 They are the same type definition.
 187         if (derived == base)
 188             return true;
 189 
 190         // 2 All of the following must be true:
 191         // 2.1 restriction is not in the subset, or in the {final} of its own {base type definition};
 192         if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 ||
 193                 (derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) {
 194             return false;
 195         }
 196 
 197         // 2.2 One of the following must be true:
 198         // 2.2.1 D's base type definition is B.
 199         XSSimpleType directBase = (XSSimpleType)derived.getBaseType();
 200         if (directBase == base)
 201             return true;
 202 
 203         // 2.2.2 D's base type definition is not the simple ur-type definition and is validly derived from B given the subset, as defined by this constraint.
 204         if (directBase != SchemaGrammar.fAnySimpleType &&
 205                 checkSimpleDerivation(directBase, base, block)) {
 206             return true;
 207         }
 208 
 209         // 2.2.3 D's {variety} is list or union and B is the simple ur-type definition.
 210         if ((derived.getVariety() == XSSimpleType.VARIETY_LIST ||
 211                 derived.getVariety() == XSSimpleType.VARIETY_UNION) &&
 212                 base == SchemaGrammar.fAnySimpleType) {
 213             return true;
 214         }
 215 
 216         // 2.2.4 B's {variety} is union and D is validly derived from a type definition in B's {member type definitions} given the subset, as defined by this constraint.
 217         if (base.getVariety() == XSSimpleType.VARIETY_UNION) {
 218             XSObjectList subUnionMemberDV = base.getMemberTypes();
 219             int subUnionSize = subUnionMemberDV.getLength();
 220             for (int i=0; i<subUnionSize; i++) {
 221                 base = (XSSimpleType)subUnionMemberDV.item(i);
 222                 if (checkSimpleDerivation(derived, base, block))
 223                     return true;
 224             }
 225         }
 226 
 227         return false;
 228     }
 229 
 230     /**
 231      * Note: this will be a private method, and it assumes that derived is not
 232      *       anyType. Another method will be introduced for public use,
 233      *       which will call this method.
 234      */
 235     private static boolean checkComplexDerivation(XSComplexTypeDecl derived, XSTypeDefinition base, short block) {
 236         // 2.1 B and D must be the same type definition.
 237         if (derived == base)
 238             return true;
 239 
 240         // 1 If B and D are not the same type definition, then the {derivation method} of D must not be in the subset.
 241         if ((derived.fDerivedBy & block) != 0)
 242             return false;
 243 
 244         // 2 One of the following must be true:
 245         XSTypeDefinition directBase = derived.fBaseType;
 246         // 2.2 B must be D's {base type definition}.
 247         if (directBase == base)
 248             return true;
 249 
 250         // 2.3 All of the following must be true:
 251         // 2.3.1 D's {base type definition} must not be the ur-type definition.
 252         if (directBase == SchemaGrammar.fAnyType ||
 253                 directBase == SchemaGrammar.fAnySimpleType) {
 254             return false;
 255         }
 256 
 257         // 2.3.2 The appropriate case among the following must be true:
 258         // 2.3.2.1 If D's {base type definition} is complex, then it must be validly derived from B given the subset as defined by this constraint.
 259         if (directBase.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
 260             return checkComplexDerivation((XSComplexTypeDecl)directBase, base, block);
 261 
 262         // 2.3.2.2 If D's {base type definition} is simple, then it must be validly derived from B given the subset as defined in Type Derivation OK (Simple) (3.14.6).
 263         if (directBase.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 264             // if base is complex type
 265             if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 266                 // if base is anyType, change base to anySimpleType,
 267                 // otherwise, not valid
 268                 if (base == SchemaGrammar.fAnyType)
 269                     base = SchemaGrammar.fAnySimpleType;
 270                 else
 271                     return false;
 272             }
 273             return checkSimpleDerivation((XSSimpleType)directBase,
 274                     (XSSimpleType)base, block);
 275         }
 276 
 277         return false;
 278     }
 279 
 280     /**
 281      * check whether a value is a valid default for some type
 282      * returns the compiled form of the value
 283      * The parameter value could be either a String or a ValidatedInfo object
 284      */
 285     public static Object ElementDefaultValidImmediate(XSTypeDefinition type, String value, ValidationContext context, ValidatedInfo vinfo) {
 286 
 287         XSSimpleType dv = null;
 288 
 289         // e-props-correct
 290         // For a string to be a valid default with respect to a type definition the appropriate case among the following must be true:
 291         // 1 If the type definition is a simple type definition, then the string must be valid with respect to that definition as defined by String Valid (3.14.4).
 292         if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 293             dv = (XSSimpleType)type;
 294         }
 295 
 296         // 2 If the type definition is a complex type definition, then all of the following must be true:
 297         else {
 298             // 2.1 its {content type} must be a simple type definition or mixed.
 299             XSComplexTypeDecl ctype = (XSComplexTypeDecl)type;
 300             // 2.2 The appropriate case among the following must be true:
 301             // 2.2.1 If the {content type} is a simple type definition, then the string must be valid with respect to that simple type definition as defined by String Valid (3.14.4).
 302             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
 303                 dv = ctype.fXSSimpleType;
 304             }
 305             // 2.2.2 If the {content type} is mixed, then the {content type}'s particle must be emptiable as defined by Particle Emptiable (3.9.6).
 306             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
 307                 if (!((XSParticleDecl)ctype.getParticle()).emptiable())
 308                     return null;
 309             }
 310             else {
 311                 return null;
 312             }
 313         }
 314 
 315         // get the simple type declaration, and validate
 316         Object actualValue = null;
 317         if (dv == null) {
 318             // complex type with mixed. to make sure that we store correct
 319             // information in vinfo and return the correct value, we use
 320             // "string" type for validation
 321             dv = STRING_TYPE;
 322         }
 323         try {
 324             // validate the original lexical rep, and set the actual value
 325             actualValue = dv.validate(value, context, vinfo);
 326             // validate the canonical lexical rep
 327             if (vinfo != null)
 328                 actualValue = dv.validate(vinfo.stringValue(), context, vinfo);
 329         } catch (InvalidDatatypeValueException ide) {
 330             return null;
 331         }
 332 
 333         return actualValue;
 334     }
 335 
 336     static void reportSchemaError(XMLErrorReporter errorReporter,
 337             SimpleLocator loc,
 338             String key, Object[] args) {
 339         if (loc != null) {
 340             errorReporter.reportError(loc, XSMessageFormatter.SCHEMA_DOMAIN,
 341                     key, args, XMLErrorReporter.SEVERITY_ERROR);
 342         }
 343         else {
 344             errorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 345                     key, args, XMLErrorReporter.SEVERITY_ERROR);
 346         }
 347     }
 348 
 349     /**
 350      * used to check the 3 constraints against each complex type
 351      * (should be each model group):
 352      * Unique Particle Attribution, Particle Derivation (Restriction),
 353      * Element Declrations Consistent.
 354      */
 355     public static void fullSchemaChecking(XSGrammarBucket grammarBucket,
 356             SubstitutionGroupHandler SGHandler,
 357             CMBuilder cmBuilder,
 358             XMLErrorReporter errorReporter) {
 359         // get all grammars, and put all substitution group information
 360         // in the substitution group handler
 361         SchemaGrammar[] grammars = grammarBucket.getGrammars();
 362         for (int i = grammars.length-1; i >= 0; i--) {
 363             SGHandler.addSubstitutionGroup(grammars[i].getSubstitutionGroups());
 364         }
 365 
 366         XSParticleDecl fakeDerived = new XSParticleDecl();
 367         XSParticleDecl fakeBase = new XSParticleDecl();
 368         fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 369         fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 370         // before worrying about complexTypes, let's get
 371         // groups redefined by restriction out of the way.
 372         for (int g = grammars.length-1; g >= 0; g--) {
 373             XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls();
 374             SimpleLocator [] rgLocators = grammars[g].getRGLocators();
 375             for(int i=0; i<redefinedGroups.length; ) {
 376                 XSGroupDecl derivedGrp = redefinedGroups[i++];
 377                 XSModelGroupImpl derivedMG = derivedGrp.fModelGroup;
 378                 XSGroupDecl baseGrp = redefinedGroups[i++];
 379                 XSModelGroupImpl baseMG = baseGrp.fModelGroup;
 380                 fakeDerived.fValue = derivedMG;
 381                 fakeBase.fValue = baseMG;
 382                 if(baseMG == null) {
 383                     if(derivedMG != null) { // can't be a restriction!
 384                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 385                                 "src-redefine.6.2.2",
 386                                 new Object[]{derivedGrp.fName, "rcase-Recurse.2"});
 387                     }
 388                 } else if (derivedMG == null) {
 389                     if (!fakeBase.emptiable()) {
 390                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 391                                 "src-redefine.6.2.2",
 392                                 new Object[]{derivedGrp.fName, "rcase-Recurse.2"});
 393                     }
 394                 } else {
 395                     try {
 396                         particleValidRestriction(fakeDerived, SGHandler, fakeBase, SGHandler);
 397                     } catch (XMLSchemaException e) {
 398                         String key = e.getKey();
 399                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 400                                 key,
 401                                 e.getArgs());
 402                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 403                                 "src-redefine.6.2.2",
 404                                 new Object[]{derivedGrp.fName, key});
 405                     }
 406                 }
 407             }
 408         }
 409 
 410         // for each complex type, check the 3 constraints.
 411         // types need to be checked
 412         XSComplexTypeDecl[] types;
 413         SimpleLocator [] ctLocators;
 414         // to hold the errors
 415         // REVISIT: do we want to report all errors? or just one?
 416         //XMLSchemaError1D errors = new XMLSchemaError1D();
 417         // whether need to check this type again;
 418         // whether only do UPA checking
 419         boolean further, fullChecked;
 420         // if do all checkings, how many need to be checked again.
 421         int keepType;
 422         // i: grammar; j: type; k: error
 423         // for all grammars
 424         SymbolHash elemTable = new SymbolHash();
 425         for (int i = grammars.length-1, j; i >= 0; i--) {
 426             // get whether to skip EDC, and types need to be checked
 427             keepType = 0;
 428             fullChecked = grammars[i].fFullChecked;
 429             types = grammars[i].getUncheckedComplexTypeDecls();
 430             ctLocators = grammars[i].getUncheckedCTLocators();
 431             // for each type
 432             for (j = 0; j < types.length; j++) {
 433                 // if we've already full-checked this grammar, then
 434                 // skip the EDC constraint
 435                 if (!fullChecked) {
 436                     // 1. Element Decl Consistent
 437                     if (types[j].fParticle!=null) {
 438                         elemTable.clear();
 439                         try {
 440                             checkElementDeclsConsistent(types[j], types[j].fParticle,
 441                                     elemTable, SGHandler);
 442                         }
 443                         catch (XMLSchemaException e) {
 444                             reportSchemaError(errorReporter, ctLocators[j],
 445                                     e.getKey(),
 446                                     e.getArgs());
 447                         }
 448                     }
 449                 }
 450 
 451                 // 2. Particle Derivation
 452 
 453                 if (types[j].fBaseType != null &&
 454                         types[j].fBaseType != SchemaGrammar.fAnyType &&
 455                         types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION &&
 456                         (types[j].fBaseType instanceof XSComplexTypeDecl)) {
 457 
 458                     XSParticleDecl derivedParticle=types[j].fParticle;
 459                     XSParticleDecl baseParticle=
 460                         ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle;
 461                     if (derivedParticle==null) {
 462                         if (baseParticle!=null && !baseParticle.emptiable()) {
 463                             reportSchemaError(errorReporter,ctLocators[j],
 464                                     "derivation-ok-restriction.5.3.2",
 465                                     new Object[]{types[j].fName, types[j].fBaseType.getName()});
 466                         }
 467                     }
 468                     else if (baseParticle!=null) {
 469                         try {
 470                             particleValidRestriction(types[j].fParticle,
 471                                     SGHandler,
 472                                     ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle,
 473                                     SGHandler);
 474                         } catch (XMLSchemaException e) {
 475                             reportSchemaError(errorReporter, ctLocators[j],
 476                                     e.getKey(),
 477                                     e.getArgs());
 478                             reportSchemaError(errorReporter, ctLocators[j],
 479                                     "derivation-ok-restriction.5.4.2",
 480                                     new Object[]{types[j].fName});
 481                         }
 482                     }
 483                     else {
 484                         reportSchemaError(errorReporter, ctLocators[j],
 485                                 "derivation-ok-restriction.5.4.2",
 486                                 new Object[]{types[j].fName});
 487                     }
 488                 }
 489                 // 3. UPA
 490                 // get the content model and check UPA
 491                 XSCMValidator cm = types[j].getContentModel(cmBuilder);
 492                 further = false;
 493                 if (cm != null) {
 494                     try {
 495                         further = cm.checkUniqueParticleAttribution(SGHandler);
 496                     } catch (XMLSchemaException e) {
 497                         reportSchemaError(errorReporter, ctLocators[j],
 498                                 e.getKey(),
 499                                 e.getArgs());
 500                     }
 501                 }
 502                 // now report all errors
 503                 // REVISIT: do we want to report all errors? or just one?
 504                 /*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) {
 505                     reportSchemaError(errorReporter, ctLocators[j],
 506                                       errors.getErrorCode(k),
 507                                       errors.getArgs(k));
 508                 }*/
 509 
 510                 // if we are doing all checkings, and this one needs further
 511                 // checking, store it in the type array.
 512                 if (!fullChecked && further)
 513                     types[keepType++] = types[j];
 514 
 515                 // clear errors for the next type.
 516                 // REVISIT: do we want to report all errors? or just one?
 517                 //errors.clear();
 518             }
 519             // we've done with the types in this grammar. if we are checking
 520             // all constraints, need to trim type array to a proper size:
 521             // only contain those need further checking.
 522             // and mark this grammar that it only needs UPA checking.
 523             if (!fullChecked) {
 524                 grammars[i].setUncheckedTypeNum(keepType);
 525                 grammars[i].fFullChecked = true;
 526             }
 527         }
 528     }
 529 
 530     /*
 531        Check that a given particle is a valid restriction of a base particle.
 532      */
 533 
 534     public static void checkElementDeclsConsistent(XSComplexTypeDecl type,
 535             XSParticleDecl particle,
 536             SymbolHash elemDeclHash,
 537             SubstitutionGroupHandler sgHandler)
 538         throws XMLSchemaException {
 539 
 540         // check for elements in the tree with the same name and namespace
 541 
 542         int pType = particle.fType;
 543 
 544         if (pType == XSParticleDecl.PARTICLE_WILDCARD)
 545             return;
 546 
 547         if (pType == XSParticleDecl.PARTICLE_ELEMENT) {
 548             XSElementDecl elem = (XSElementDecl)(particle.fValue);
 549             findElemInTable(type, elem, elemDeclHash);
 550 
 551             if (elem.fScope == XSConstants.SCOPE_GLOBAL) {
 552                 // Check for subsitution groups.
 553                 XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem);
 554                 for (int i = 0; i < subGroup.length; i++) {
 555                     findElemInTable(type, subGroup[i], elemDeclHash);
 556                 }
 557             }
 558             return;
 559         }
 560 
 561         XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue;
 562         for (int i = 0; i < group.fParticleCount; i++)
 563             checkElementDeclsConsistent(type, group.fParticles[i], elemDeclHash, sgHandler);
 564     }
 565 
 566     public static void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem,
 567             SymbolHash elemDeclHash)
 568         throws XMLSchemaException {
 569 
 570         // How can we avoid this concat?  LM.
 571         String name = elem.fName + "," + elem.fTargetNamespace;
 572 
 573         XSElementDecl existingElem = null;
 574         if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) {
 575             // just add it in
 576             elemDeclHash.put(name, elem);
 577         }
 578         else {
 579             // If this is the same check element, we're O.K.
 580             if (elem == existingElem)
 581                 return;
 582 
 583             if (elem.fType != existingElem.fType) {
 584                 // Types are not the same
 585                 throw new XMLSchemaException("cos-element-consistent",
 586                         new Object[] {type.fName, elem.fName});
 587 
 588             }
 589         }
 590     }
 591 
 592     // Check that a given particle is a valid restriction of a base particle.
 593     //
 594     // IHR: 2006/11/17
 595     // Returns a boolean indicating if there has been expansion of substitution group
 596     // in the bParticle.
 597     // With this information the checkRecurseLax function knows when is
 598     // to keep the order and when to ignore it.
 599     private static boolean particleValidRestriction(XSParticleDecl dParticle,
 600             SubstitutionGroupHandler dSGHandler,
 601             XSParticleDecl bParticle,
 602             SubstitutionGroupHandler bSGHandler)
 603         throws XMLSchemaException {
 604         return particleValidRestriction(dParticle, dSGHandler, bParticle, bSGHandler, true);
 605     }
 606 
 607     private static boolean particleValidRestriction(XSParticleDecl dParticle,
 608             SubstitutionGroupHandler dSGHandler,
 609             XSParticleDecl bParticle,
 610             SubstitutionGroupHandler bSGHandler,
 611             boolean checkWCOccurrence)
 612         throws XMLSchemaException {
 613 
 614         Vector dChildren = null;
 615         Vector bChildren = null;
 616         int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN;
 617         int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN;
 618 
 619         // By default there has been no expansion
 620         boolean bExpansionHappened = false;
 621 
 622         // Check for empty particles.   If either base or derived particle is empty,
 623         // (and the other isn't) it's an error.
 624         if (dParticle.isEmpty() && !bParticle.emptiable()) {
 625             throw new XMLSchemaException("cos-particle-restrict.a", null);
 626         }
 627         else if (!dParticle.isEmpty() && bParticle.isEmpty()) {
 628             throw new XMLSchemaException("cos-particle-restrict.b", null);
 629         }
 630 
 631         //
 632         // Do setup prior to invoking the Particle (Restriction) cases.
 633         // This involves:
 634         //   - removing pointless occurrences for groups, and retrieving a vector of
 635         //     non-pointless children
 636         //   - turning top-level elements with substitution groups into CHOICE groups.
 637         //
 638 
 639         short dType = dParticle.fType;
 640         //
 641         // Handle pointless groups for the derived particle
 642         //
 643         if (dType == XSParticleDecl.PARTICLE_MODELGROUP) {
 644             dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor;
 645 
 646             // Find a group, starting with this particle, with more than 1 child.   There
 647             // may be none, and the particle of interest trivially becomes an element or
 648             // wildcard.
 649             XSParticleDecl dtmp = getNonUnaryGroup(dParticle);
 650             if (dtmp != dParticle) {
 651                 // Particle has been replaced.   Retrieve new type info.
 652                 dParticle = dtmp;
 653                 dType = dParticle.fType;
 654                 if (dType == XSParticleDecl.PARTICLE_MODELGROUP)
 655                     dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor;
 656             }
 657 
 658             // Fill in a vector with the children of the particle, removing any
 659             // pointless model groups in the process.
 660             dChildren = removePointlessChildren(dParticle);
 661         }
 662 
 663         int dMinOccurs = dParticle.fMinOccurs;
 664         int dMaxOccurs = dParticle.fMaxOccurs;
 665 
 666         //
 667         // For elements which are the heads of substitution groups, treat as CHOICE
 668         //
 669         if (dSGHandler != null && dType == XSParticleDecl.PARTICLE_ELEMENT) {
 670             XSElementDecl dElement = (XSElementDecl)dParticle.fValue;
 671 
 672             if (dElement.fScope == XSConstants.SCOPE_GLOBAL) {
 673                 // Check for subsitution groups.   Treat any element that has a
 674                 // subsitution group as a choice.   Fill in the children vector with the
 675                 // members of the substitution group
 676                 XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement);
 677                 if (subGroup.length >0 ) {
 678                     // Now, set the type to be CHOICE.  The "group" will have the same
 679                     // occurrence information as the original particle.
 680                     dType = XSModelGroupImpl.MODELGROUP_CHOICE;
 681                     dMinEffectiveTotalRange = dMinOccurs;
 682                     dMaxEffectiveTotalRange = dMaxOccurs;
 683 
 684                     // Fill in the vector of children
 685                     dChildren = new Vector(subGroup.length+1);
 686                     for (int i = 0; i < subGroup.length; i++) {
 687                         addElementToParticleVector(dChildren, subGroup[i]);
 688                     }
 689                     addElementToParticleVector(dChildren, dElement);
 690                     Collections.sort(dChildren, ELEMENT_PARTICLE_COMPARATOR);
 691 
 692                     // Set the handler to null, to indicate that we've finished handling
 693                     // substitution groups for this particle.
 694                     dSGHandler = null;
 695                 }
 696             }
 697         }
 698 
 699         short bType = bParticle.fType;
 700         //
 701         // Handle pointless groups for the base particle
 702         //
 703         if (bType == XSParticleDecl.PARTICLE_MODELGROUP) {
 704             bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor;
 705 
 706             // Find a group, starting with this particle, with more than 1 child.   There
 707             // may be none, and the particle of interest trivially becomes an element or
 708             // wildcard.
 709             XSParticleDecl btmp = getNonUnaryGroup(bParticle);
 710             if (btmp != bParticle) {
 711                 // Particle has been replaced.   Retrieve new type info.
 712                 bParticle = btmp;
 713                 bType = bParticle.fType;
 714                 if (bType == XSParticleDecl.PARTICLE_MODELGROUP)
 715                     bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor;
 716             }
 717 
 718             // Fill in a vector with the children of the particle, removing any
 719             // pointless model groups in the process.
 720             bChildren = removePointlessChildren(bParticle);
 721         }
 722 
 723         int bMinOccurs = bParticle.fMinOccurs;
 724         int bMaxOccurs = bParticle.fMaxOccurs;
 725 
 726         if (bSGHandler != null && bType == XSParticleDecl.PARTICLE_ELEMENT) {
 727             XSElementDecl bElement = (XSElementDecl)bParticle.fValue;
 728 
 729             if (bElement.fScope == XSConstants.SCOPE_GLOBAL) {
 730                 // Check for subsitution groups.   Treat any element that has a
 731                 // subsitution group as a choice.   Fill in the children vector with the
 732                 // members of the substitution group
 733                 XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement);
 734                 if (bsubGroup.length >0 ) {
 735                     // Now, set the type to be CHOICE
 736                     bType = XSModelGroupImpl.MODELGROUP_CHOICE;
 737 
 738                     bChildren = new Vector(bsubGroup.length+1);
 739                     for (int i = 0; i < bsubGroup.length; i++) {
 740                         addElementToParticleVector(bChildren, bsubGroup[i]);
 741                     }
 742                     addElementToParticleVector(bChildren, bElement);
 743                     Collections.sort(bChildren, ELEMENT_PARTICLE_COMPARATOR);
 744                     // Set the handler to null, to indicate that we've finished handling
 745                     // substitution groups for this particle.
 746                     bSGHandler = null;
 747 
 748                     // if we are here expansion of bParticle happened
 749                     bExpansionHappened = true;
 750                 }
 751             }
 752         }
 753 
 754         //
 755         // O.K. - Figure out which particle derivation rule applies and call it
 756         //
 757         switch (dType) {
 758             case XSParticleDecl.PARTICLE_ELEMENT:
 759             {
 760                 switch (bType) {
 761 
 762                     // Elt:Elt NameAndTypeOK
 763                     case XSParticleDecl.PARTICLE_ELEMENT:
 764                     {
 765                         checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs,
 766                                 (XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs);
 767                         return bExpansionHappened;
 768                     }
 769 
 770                     // Elt:Any NSCompat
 771                     case XSParticleDecl.PARTICLE_WILDCARD:
 772                     {
 773                         checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs,
 774                                 (XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs,
 775                                 checkWCOccurrence);
 776                         return bExpansionHappened;
 777                     }
 778 
 779                     // Elt:All RecurseAsIfGroup
 780                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 781                     {
 782                         // Treat the element as if it were in a group of the same type
 783                         // as the base Particle
 784                         dChildren = new Vector();
 785                         dChildren.addElement(dParticle);
 786 
 787                         checkRecurseLax(dChildren, 1, 1, dSGHandler,
 788                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 789                         return bExpansionHappened;
 790                     }
 791                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 792                     case XSModelGroupImpl.MODELGROUP_ALL:
 793                     {
 794                         // Treat the element as if it were in a group of the same type
 795                         // as the base Particle
 796                         dChildren = new Vector();
 797                         dChildren.addElement(dParticle);
 798 
 799                         checkRecurse(dChildren, 1, 1, dSGHandler,
 800                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 801                         return bExpansionHappened;
 802                     }
 803 
 804                     default:
 805                     {
 806                         throw new XMLSchemaException("Internal-Error",
 807                                 new Object[]{"in particleValidRestriction"});
 808                     }
 809                 }
 810             }
 811 
 812             case XSParticleDecl.PARTICLE_WILDCARD:
 813             {
 814                 switch (bType) {
 815 
 816                     // Any:Any NSSubset
 817                     case XSParticleDecl.PARTICLE_WILDCARD:
 818                     {
 819                         checkNSSubset((XSWildcardDecl)dParticle.fValue, dMinOccurs, dMaxOccurs,
 820                                 (XSWildcardDecl)bParticle.fValue, bMinOccurs, bMaxOccurs);
 821                         return bExpansionHappened;
 822                     }
 823 
 824                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 825                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 826                     case XSModelGroupImpl.MODELGROUP_ALL:
 827                     case XSParticleDecl.PARTICLE_ELEMENT:
 828                     {
 829                         throw new XMLSchemaException("cos-particle-restrict.2",
 830                                 new Object[]{"any:choice,sequence,all,elt"});
 831                     }
 832 
 833                     default:
 834                     {
 835                         throw new XMLSchemaException("Internal-Error",
 836                                 new Object[]{"in particleValidRestriction"});
 837                     }
 838                 }
 839             }
 840 
 841             case XSModelGroupImpl.MODELGROUP_ALL:
 842             {
 843                 switch (bType) {
 844 
 845                     // All:Any NSRecurseCheckCardinality
 846                     case XSParticleDecl.PARTICLE_WILDCARD:
 847                     {
 848                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 849                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 850                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 851                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 852 
 853                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 854                                 dMaxEffectiveTotalRange,
 855                                 dSGHandler,
 856                                 bParticle,bMinOccurs,bMaxOccurs,
 857                                 checkWCOccurrence);
 858 
 859                         return bExpansionHappened;
 860                     }
 861 
 862                     case XSModelGroupImpl.MODELGROUP_ALL:
 863                     {
 864                         checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 865                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 866                         return bExpansionHappened;
 867                     }
 868 
 869                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 870                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 871                     case XSParticleDecl.PARTICLE_ELEMENT:
 872                     {
 873                         throw new XMLSchemaException("cos-particle-restrict.2",
 874                                 new Object[]{"all:choice,sequence,elt"});
 875                     }
 876 
 877                     default:
 878                     {
 879                         throw new XMLSchemaException("Internal-Error",
 880                                 new Object[]{"in particleValidRestriction"});
 881                     }
 882                 }
 883             }
 884 
 885             case XSModelGroupImpl.MODELGROUP_CHOICE:
 886             {
 887                 switch (bType) {
 888 
 889                     // Choice:Any NSRecurseCheckCardinality
 890                     case XSParticleDecl.PARTICLE_WILDCARD:
 891                     {
 892                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 893                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 894                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 895                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 896 
 897                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 898                                 dMaxEffectiveTotalRange,
 899                                 dSGHandler,
 900                                 bParticle,bMinOccurs,bMaxOccurs,
 901                                 checkWCOccurrence);
 902                         return bExpansionHappened;
 903                     }
 904 
 905                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 906                     {
 907                         checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 908                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 909                         return bExpansionHappened;
 910                     }
 911 
 912                     case XSModelGroupImpl.MODELGROUP_ALL:
 913                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 914                     case XSParticleDecl.PARTICLE_ELEMENT:
 915                     {
 916                         throw new XMLSchemaException("cos-particle-restrict.2",
 917                                 new Object[]{"choice:all,sequence,elt"});
 918                     }
 919 
 920                     default:
 921                     {
 922                         throw new XMLSchemaException("Internal-Error",
 923                                 new Object[]{"in particleValidRestriction"});
 924                     }
 925                 }
 926             }
 927 
 928 
 929             case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 930             {
 931                 switch (bType) {
 932 
 933                     // Choice:Any NSRecurseCheckCardinality
 934                     case XSParticleDecl.PARTICLE_WILDCARD:
 935                     {
 936                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 937                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 938                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 939                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 940 
 941                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 942                                 dMaxEffectiveTotalRange,
 943                                 dSGHandler,
 944                                 bParticle,bMinOccurs,bMaxOccurs,
 945                                 checkWCOccurrence);
 946                         return bExpansionHappened;
 947                     }
 948 
 949                     case XSModelGroupImpl.MODELGROUP_ALL:
 950                     {
 951                         checkRecurseUnordered(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 952                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 953                         return bExpansionHappened;
 954                     }
 955 
 956                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 957                     {
 958                         checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 959                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 960                         return bExpansionHappened;
 961                     }
 962 
 963                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 964                     {
 965                         int min1 = dMinOccurs * dChildren.size();
 966                         int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED)?
 967                                 dMaxOccurs : dMaxOccurs * dChildren.size();
 968                         checkMapAndSum(dChildren, min1, max1, dSGHandler,
 969                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 970                         return bExpansionHappened;
 971                     }
 972 
 973                     case XSParticleDecl.PARTICLE_ELEMENT:
 974                     {
 975                         throw new XMLSchemaException("cos-particle-restrict.2",
 976                                 new Object[]{"seq:elt"});
 977                     }
 978 
 979                     default:
 980                     {
 981                         throw new XMLSchemaException("Internal-Error",
 982                                 new Object[]{"in particleValidRestriction"});
 983                     }
 984                 }
 985             }
 986 
 987         }
 988 
 989         return bExpansionHappened;
 990     }
 991 
 992     private static void addElementToParticleVector (Vector v, XSElementDecl d)  {
 993 
 994         XSParticleDecl p = new XSParticleDecl();
 995         p.fValue = d;
 996         p.fType = XSParticleDecl.PARTICLE_ELEMENT;
 997         v.addElement(p);
 998 
 999     }
1000 
1001     private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) {
1002 
1003         if (p.fType == XSParticleDecl.PARTICLE_ELEMENT ||
1004                 p.fType == XSParticleDecl.PARTICLE_WILDCARD)
1005             return p;
1006 
1007         if (p.fMinOccurs==1 && p.fMaxOccurs==1 &&
1008                 p.fValue!=null && ((XSModelGroupImpl)p.fValue).fParticleCount == 1)
1009             return getNonUnaryGroup(((XSModelGroupImpl)p.fValue).fParticles[0]);
1010         else
1011             return p;
1012     }
1013 
1014     private static Vector removePointlessChildren(XSParticleDecl p)  {
1015 
1016         if (p.fType == XSParticleDecl.PARTICLE_ELEMENT ||
1017                 p.fType == XSParticleDecl.PARTICLE_WILDCARD)
1018             return null;
1019 
1020         Vector children = new Vector();
1021 
1022         XSModelGroupImpl group = (XSModelGroupImpl)p.fValue;
1023         for (int i = 0; i < group.fParticleCount; i++)
1024             gatherChildren(group.fCompositor, group.fParticles[i], children);
1025 
1026         return children;
1027     }
1028 
1029 
1030     private static void gatherChildren(int parentType, XSParticleDecl p, Vector children) {
1031 
1032         int min = p.fMinOccurs;
1033         int max = p.fMaxOccurs;
1034         int type = p.fType;
1035         if (type == XSParticleDecl.PARTICLE_MODELGROUP)
1036             type = ((XSModelGroupImpl)p.fValue).fCompositor;
1037 
1038         if (type == XSParticleDecl.PARTICLE_ELEMENT ||
1039                 type== XSParticleDecl.PARTICLE_WILDCARD) {
1040             children.addElement(p);
1041             return;
1042         }
1043 
1044         if (! (min==1 && max==1)) {
1045             children.addElement(p);
1046         }
1047         else if (parentType == type) {
1048             XSModelGroupImpl group = (XSModelGroupImpl)p.fValue;
1049             for (int i = 0; i < group.fParticleCount; i++)
1050                 gatherChildren(type, group.fParticles[i], children);
1051         }
1052         else if (!p.isEmpty()) {
1053             children.addElement(p);
1054         }
1055 
1056     }
1057 
1058     private static void checkNameAndTypeOK(XSElementDecl dElement, int dMin, int dMax,
1059             XSElementDecl bElement, int bMin, int bMax)
1060         throws XMLSchemaException {
1061 
1062 
1063         //
1064         // Check that the names are the same
1065         //
1066         if (dElement.fName != bElement.fName ||
1067                 dElement.fTargetNamespace != bElement.fTargetNamespace) {
1068             throw new XMLSchemaException(
1069                     "rcase-NameAndTypeOK.1",new Object[]{dElement.fName,
1070                             dElement.fTargetNamespace, bElement.fName, bElement.fTargetNamespace});
1071         }
1072 
1073         //
1074         // Check nillable
1075         //
1076         if (!bElement.getNillable() && dElement.getNillable()) {
1077             throw new XMLSchemaException("rcase-NameAndTypeOK.2",
1078                     new Object[]{dElement.fName});
1079         }
1080 
1081         //
1082         // Check occurrence range
1083         //
1084         if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) {
1085             throw new XMLSchemaException("rcase-NameAndTypeOK.3",
1086                     new Object[]{
1087                     dElement.fName,
1088                     Integer.toString(dMin),
1089                     dMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(dMax),
1090                             Integer.toString(bMin),
1091                             bMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(bMax)});
1092         }
1093 
1094         //
1095         // Check for consistent fixed values
1096         //
1097         if (bElement.getConstraintType() == XSConstants.VC_FIXED) {
1098             // derived one has to have a fixed value
1099             if (dElement.getConstraintType() != XSConstants.VC_FIXED) {
1100                 throw new XMLSchemaException("rcase-NameAndTypeOK.4.a",
1101                         new Object[]{dElement.fName, bElement.fDefault.stringValue()});
1102             }
1103 
1104             // get simple type
1105             boolean isSimple = false;
1106             if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE ||
1107                     ((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
1108                 isSimple = true;
1109             }
1110 
1111             // if there is no simple type, then compare based on string
1112             if (!isSimple && !bElement.fDefault.normalizedValue.equals(dElement.fDefault.normalizedValue) ||
1113                     isSimple && !bElement.fDefault.actualValue.equals(dElement.fDefault.actualValue)) {
1114                 throw new XMLSchemaException("rcase-NameAndTypeOK.4.b",
1115                         new Object[]{dElement.fName,
1116                         dElement.fDefault.stringValue(),
1117                         bElement.fDefault.stringValue()});
1118             }
1119         }
1120 
1121         //
1122         // Check identity constraints
1123         //
1124         checkIDConstraintRestriction(dElement, bElement);
1125 
1126         //
1127         // Check for disallowed substitutions
1128         //
1129         int blockSet1 = dElement.fBlock;
1130         int blockSet2 = bElement.fBlock;
1131         if (((blockSet1 & blockSet2)!=blockSet2) ||
1132                 (blockSet1==XSConstants.DERIVATION_NONE && blockSet2!=XSConstants.DERIVATION_NONE))
1133             throw new XMLSchemaException("rcase-NameAndTypeOK.6",
1134                     new Object[]{dElement.fName});
1135 
1136 
1137         //
1138         // Check that the derived element's type is derived from the base's.
1139         //
1140         if (!checkTypeDerivationOk(dElement.fType, bElement.fType,
1141                 (short)(XSConstants.DERIVATION_EXTENSION|XSConstants.DERIVATION_LIST|XSConstants.DERIVATION_UNION))) {
1142             throw new XMLSchemaException("rcase-NameAndTypeOK.7",
1143                     new Object[]{dElement.fName, dElement.fType.getName(), bElement.fType.getName()});
1144         }
1145 
1146     }
1147 
1148 
1149     private static void checkIDConstraintRestriction(XSElementDecl derivedElemDecl,
1150             XSElementDecl baseElemDecl)
1151         throws XMLSchemaException {
1152         // TODO
1153     } // checkIDConstraintRestriction
1154 
1155 
1156     private static boolean checkOccurrenceRange(int min1, int max1, int min2, int max2) {
1157 
1158         if ((min1 >= min2) &&
1159                 ((max2==SchemaSymbols.OCCURRENCE_UNBOUNDED) ||
1160                         (max1!=SchemaSymbols.OCCURRENCE_UNBOUNDED && max1<=max2)))
1161             return true;
1162         else
1163             return false;
1164     }
1165 
1166     private static void checkNSCompat(XSElementDecl elem, int min1, int max1,
1167             XSWildcardDecl wildcard, int min2, int max2,
1168             boolean checkWCOccurrence)
1169         throws XMLSchemaException {
1170 
1171         // check Occurrence ranges
1172         if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) {
1173             throw new XMLSchemaException("rcase-NSCompat.2",
1174                     new Object[]{
1175                     elem.fName,
1176                     Integer.toString(min1),
1177                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1178                             Integer.toString(min2),
1179                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1180         }
1181 
1182         // check wildcard allows namespace of element
1183         if (!wildcard.allowNamespace(elem.fTargetNamespace))  {
1184             throw new XMLSchemaException("rcase-NSCompat.1",
1185                     new Object[]{elem.fName,elem.fTargetNamespace});
1186         }
1187 
1188     }
1189 
1190     private static void checkNSSubset(XSWildcardDecl dWildcard, int min1, int max1,
1191             XSWildcardDecl bWildcard, int min2, int max2)
1192         throws XMLSchemaException {
1193 
1194         // check Occurrence ranges
1195         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1196             throw new XMLSchemaException("rcase-NSSubset.2", new Object[]{
1197                     Integer.toString(min1),
1198                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1199                             Integer.toString(min2),
1200                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1201         }
1202 
1203         // check wildcard subset
1204         if (!dWildcard.isSubsetOf(bWildcard)) {
1205             throw new XMLSchemaException("rcase-NSSubset.1", null);
1206         }
1207 
1208         if (dWildcard.weakerProcessContents(bWildcard)) {
1209             throw new XMLSchemaException("rcase-NSSubset.3",
1210                     new Object[]{dWildcard.getProcessContentsAsString(),
1211                     bWildcard.getProcessContentsAsString()});
1212         }
1213 
1214     }
1215 
1216 
1217     private static void checkNSRecurseCheckCardinality(Vector children, int min1, int max1,
1218             SubstitutionGroupHandler dSGHandler,
1219             XSParticleDecl wildcard, int min2, int max2,
1220             boolean checkWCOccurrence)
1221         throws XMLSchemaException {
1222 
1223 
1224         // check Occurrence ranges
1225         if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) {
1226             throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.2", new Object[]{
1227                     Integer.toString(min1),
1228                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1229                             Integer.toString(min2),
1230                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1231         }
1232 
1233         // Check that each member of the group is a valid restriction of the wildcard
1234         int count = children.size();
1235         try {
1236             for (int i = 0; i < count; i++) {
1237                 XSParticleDecl particle1 = (XSParticleDecl)children.elementAt(i);
1238                 particleValidRestriction(particle1, dSGHandler, wildcard, null, false);
1239 
1240             }
1241         }
1242         // REVISIT: should we really just ignore original cause of this error?
1243         //          how can we report it?
1244         catch (XMLSchemaException e) {
1245             throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null);
1246         }
1247 
1248     }
1249 
1250     private static void checkRecurse(Vector dChildren, int min1, int max1,
1251             SubstitutionGroupHandler dSGHandler,
1252             Vector bChildren, int min2, int max2,
1253             SubstitutionGroupHandler bSGHandler)
1254         throws XMLSchemaException {
1255 
1256         // check Occurrence ranges
1257         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1258             throw new XMLSchemaException("rcase-Recurse.1", new Object[]{
1259                     Integer.toString(min1),
1260                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1261                     Integer.toString(min2),
1262                     max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1263         }
1264 
1265         int count1= dChildren.size();
1266         int count2= bChildren.size();
1267 
1268         int current = 0;
1269         label: for (int i = 0; i<count1; i++) {
1270 
1271             XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i);
1272             for (int j = current; j<count2; j++) {
1273                 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1274                 current +=1;
1275                 try {
1276                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1277                     continue label;
1278                 }
1279                 catch (XMLSchemaException e) {
1280                     if (!particle2.emptiable())
1281                         throw new XMLSchemaException("rcase-Recurse.2", null);
1282                 }
1283             }
1284             throw new XMLSchemaException("rcase-Recurse.2", null);
1285         }
1286 
1287         // Now, see if there are some elements in the base we didn't match up
1288         for (int j=current; j < count2; j++) {
1289             XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1290             if (!particle2.emptiable()) {
1291                 throw new XMLSchemaException("rcase-Recurse.2", null);
1292             }
1293         }
1294 
1295     }
1296 
1297     private static void checkRecurseUnordered(Vector dChildren, int min1, int max1,
1298             SubstitutionGroupHandler dSGHandler,
1299             Vector bChildren, int min2, int max2,
1300             SubstitutionGroupHandler bSGHandler)
1301         throws XMLSchemaException {
1302 
1303 
1304         // check Occurrence ranges
1305         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1306             throw new XMLSchemaException("rcase-RecurseUnordered.1", new Object[]{
1307                     Integer.toString(min1),
1308                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1309                     Integer.toString(min2),
1310                     max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1311         }
1312 
1313         int count1= dChildren.size();
1314         int count2 = bChildren.size();
1315 
1316         boolean foundIt[] = new boolean[count2];
1317 
1318         label: for (int i = 0; i<count1; i++) {
1319             XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i);
1320 
1321             for (int j = 0; j<count2; j++) {
1322                 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1323                 try {
1324                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1325                     if (foundIt[j])
1326                         throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1327                     else
1328                         foundIt[j]=true;
1329 
1330                     continue label;
1331                 }
1332                 catch (XMLSchemaException e) {
1333                 }
1334             }
1335             // didn't find a match.  Detect an error
1336             throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1337         }
1338 
1339         // Now, see if there are some elements in the base we didn't match up
1340         for (int j=0; j < count2; j++) {
1341             XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1342             if (!foundIt[j] && !particle2.emptiable()) {
1343                 throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1344             }
1345         }
1346 
1347     }
1348 
1349     private static void checkRecurseLax(Vector dChildren, int min1, int max1,
1350             SubstitutionGroupHandler dSGHandler,
1351             Vector bChildren, int min2, int max2,
1352             SubstitutionGroupHandler  bSGHandler)
1353         throws XMLSchemaException {
1354 
1355         // check Occurrence ranges
1356         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1357             throw new XMLSchemaException("rcase-RecurseLax.1", new Object[]{
1358                     Integer.toString(min1),
1359                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1360                             Integer.toString(min2),
1361                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1362         }
1363 
1364         int count1= dChildren.size();
1365         int count2 = bChildren.size();
1366 
1367         int current = 0;
1368         label: for (int i = 0; i<count1; i++) {
1369 
1370             XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i);
1371             for (int j = current; j<count2; j++) {
1372                 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1373                 current +=1;
1374                 try {
1375                     // IHR: go back one element on b list because the next element may match
1376                     // this as well.
1377                     if (particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler))
1378                         current--;
1379                     continue label;
1380                 }
1381                 catch (XMLSchemaException e) {
1382                 }
1383             }
1384             // didn't find a match.  Detect an error
1385             throw new XMLSchemaException("rcase-RecurseLax.2", null);
1386 
1387         }
1388 
1389     }
1390 
1391     private static void checkMapAndSum(Vector dChildren, int min1, int max1,
1392             SubstitutionGroupHandler dSGHandler,
1393             Vector bChildren, int min2, int max2,
1394             SubstitutionGroupHandler bSGHandler)
1395         throws XMLSchemaException {
1396 
1397         // See if the sequence group is a valid restriction of the choice
1398 
1399         // Here is an example of a valid restriction:
1400         //   <choice minOccurs="2">
1401         //       <a/>
1402         //       <b/>
1403         //       <c/>
1404         //   </choice>
1405         //
1406         //   <sequence>
1407         //        <b/>
1408         //        <a/>
1409         //   </sequence>
1410 
1411         // check Occurrence ranges
1412         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1413             throw new XMLSchemaException("rcase-MapAndSum.2",
1414                     new Object[]{Integer.toString(min1),
1415                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1416                             Integer.toString(min2),
1417                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1418         }
1419 
1420         int count1 = dChildren.size();
1421         int count2 = bChildren.size();
1422 
1423         label: for (int i = 0; i<count1; i++) {
1424 
1425             XSParticleDecl particle1 = (XSParticleDecl)dChildren.elementAt(i);
1426             for (int j = 0; j<count2; j++) {
1427                 XSParticleDecl particle2 = (XSParticleDecl)bChildren.elementAt(j);
1428                 try {
1429                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1430                     continue label;
1431                 }
1432                 catch (XMLSchemaException e) {
1433                 }
1434             }
1435             // didn't find a match.  Detect an error
1436             throw new XMLSchemaException("rcase-MapAndSum.1", null);
1437         }
1438     }
1439     // to check whether two element overlap, as defined in constraint UPA
1440     public static boolean overlapUPA(XSElementDecl element1,
1441             XSElementDecl element2,
1442             SubstitutionGroupHandler sgHandler) {
1443         // if the two element have the same name and namespace,
1444         if (element1.fName == element2.fName &&
1445                 element1.fTargetNamespace == element2.fTargetNamespace) {
1446             return true;
1447         }
1448 
1449         // or if there is an element decl in element1's substitution group,
1450         // who has the same name/namespace with element2
1451         XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element1);
1452         for (int i = subGroup.length-1; i >= 0; i--) {
1453             if (subGroup[i].fName == element2.fName &&
1454                     subGroup[i].fTargetNamespace == element2.fTargetNamespace) {
1455                 return true;
1456             }
1457         }
1458 
1459         // or if there is an element decl in element2's substitution group,
1460         // who has the same name/namespace with element1
1461         subGroup = sgHandler.getSubstitutionGroup(element2);
1462         for (int i = subGroup.length-1; i >= 0; i--) {
1463             if (subGroup[i].fName == element1.fName &&
1464                     subGroup[i].fTargetNamespace == element1.fTargetNamespace) {
1465                 return true;
1466             }
1467         }
1468 
1469         return false;
1470     }
1471 
1472     // to check whether an element overlaps with a wildcard,
1473     // as defined in constraint UPA
1474     public static boolean overlapUPA(XSElementDecl element,
1475             XSWildcardDecl wildcard,
1476             SubstitutionGroupHandler sgHandler) {
1477         // if the wildcard allows the element
1478         if (wildcard.allowNamespace(element.fTargetNamespace))
1479             return true;
1480 
1481         // or if the wildcard allows any element in the substitution group
1482         XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element);
1483         for (int i = subGroup.length-1; i >= 0; i--) {
1484             if (wildcard.allowNamespace(subGroup[i].fTargetNamespace))
1485                 return true;
1486         }
1487 
1488         return false;
1489     }
1490 
1491     public static boolean overlapUPA(XSWildcardDecl wildcard1,
1492             XSWildcardDecl wildcard2) {
1493         // if the intersection of the two wildcard is not empty list
1494         XSWildcardDecl intersect = wildcard1.performIntersectionWith(wildcard2, wildcard1.fProcessContents);
1495         if (intersect == null ||
1496                 intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST ||
1497                 intersect.fNamespaceList.length != 0) {
1498             return true;
1499         }
1500 
1501         return false;
1502     }
1503 
1504     // call one of the above methods according to the type of decls
1505     public static boolean overlapUPA(Object decl1, Object decl2,
1506             SubstitutionGroupHandler sgHandler) {
1507         if (decl1 instanceof XSElementDecl) {
1508             if (decl2 instanceof XSElementDecl) {
1509                 return overlapUPA((XSElementDecl)decl1,
1510                         (XSElementDecl)decl2,
1511                         sgHandler);
1512             }
1513             else {
1514                 return overlapUPA((XSElementDecl)decl1,
1515                         (XSWildcardDecl)decl2,
1516                         sgHandler);
1517             }
1518         }
1519         else {
1520             if (decl2 instanceof XSElementDecl) {
1521                 return overlapUPA((XSElementDecl)decl2,
1522                         (XSWildcardDecl)decl1,
1523                         sgHandler);
1524             }
1525             else {
1526                 return overlapUPA((XSWildcardDecl)decl1,
1527                         (XSWildcardDecl)decl2);
1528             }
1529         }
1530     }
1531 
1532 } // class XSContraints