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