0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.xerces.impl.xs;
0019:
0020: import org.apache.xerces.impl.dv.XSSimpleType;
0021: import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
0022: import org.apache.xerces.impl.dv.ValidatedInfo;
0023: import org.apache.xerces.impl.XMLErrorReporter;
0024: import org.apache.xerces.impl.xs.models.CMBuilder;
0025: import org.apache.xerces.impl.xs.models.XSCMValidator;
0026: import org.apache.xerces.impl.xs.util.SimpleLocator;
0027: import org.apache.xerces.xs.XSConstants;
0028: import org.apache.xerces.xs.XSObjectList;
0029: import org.apache.xerces.xs.XSTypeDefinition;
0030: import org.apache.xerces.impl.dv.ValidationContext;
0031: import org.apache.xerces.util.SymbolHash;
0032:
0033: import java.util.Collections;
0034: import java.util.Comparator;
0035: import java.util.Vector;
0036:
0037: /**
0038: * Constraints shared by traversers and validator
0039: *
0040: * @xerces.internal
0041: *
0042: * @author Sandy Gao, IBM
0043: *
0044: * @version $Id: XSConstraints.java 573322 2007-09-06 16:48:47Z peterjm $
0045: */
0046: public class XSConstraints {
0047:
0048: // IHR: Visited on 2006-11-17
0049: // Added a boolean return value to particleValidRestriction (it was a void function)
0050: // to help the checkRecurseLax to know when expansion has happened and no order is required
0051: // (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com)
0052:
0053: static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED - 1;
0054: static final XSSimpleType STRING_TYPE = (XSSimpleType) SchemaGrammar.SG_SchemaNS
0055: .getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING);
0056:
0057: private static final Comparator ELEMENT_PARTICLE_COMPARATOR = new Comparator() {
0058:
0059: public int compare(Object o1, Object o2) {
0060: XSParticleDecl pDecl1 = (XSParticleDecl) o1;
0061: XSParticleDecl pDecl2 = (XSParticleDecl) o2;
0062: XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue;
0063: XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue;
0064:
0065: String namespace1 = decl1.getNamespace();
0066: String namespace2 = decl2.getNamespace();
0067: String name1 = decl1.getName();
0068: String name2 = decl2.getName();
0069:
0070: boolean sameNamespace = (namespace1 == namespace2);
0071: int namespaceComparison = 0;
0072:
0073: if (!sameNamespace) {
0074: if (namespace1 != null) {
0075: if (namespace2 != null) {
0076: namespaceComparison = namespace1
0077: .compareTo(namespace2);
0078: } else {
0079: namespaceComparison = 1;
0080: }
0081: } else {
0082: namespaceComparison = -1;
0083: }
0084: }
0085: //This assumes that the names are never null.
0086: return namespaceComparison != 0 ? namespaceComparison
0087: : name1.compareTo(name2);
0088: }
0089: };
0090:
0091: /**
0092: * check whether derived is valid derived from base, given a subset
0093: * of {restriction, extension}.B
0094: */
0095: public static boolean checkTypeDerivationOk(
0096: XSTypeDefinition derived, XSTypeDefinition base, short block) {
0097: // if derived is anyType, then it's valid only if base is anyType too
0098: if (derived == SchemaGrammar.fAnyType)
0099: return derived == base;
0100: // if derived is anySimpleType, then it's valid only if the base
0101: // is ur-type
0102: if (derived == SchemaGrammar.fAnySimpleType) {
0103: return (base == SchemaGrammar.fAnyType || base == SchemaGrammar.fAnySimpleType);
0104: }
0105:
0106: // if derived is simple type
0107: if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
0108: // if base is complex type
0109: if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
0110: // if base is anyType, change base to anySimpleType,
0111: // otherwise, not valid
0112: if (base == SchemaGrammar.fAnyType)
0113: base = SchemaGrammar.fAnySimpleType;
0114: else
0115: return false;
0116: }
0117: return checkSimpleDerivation((XSSimpleType) derived,
0118: (XSSimpleType) base, block);
0119: } else {
0120: return checkComplexDerivation((XSComplexTypeDecl) derived,
0121: base, block);
0122: }
0123: }
0124:
0125: /**
0126: * check whether simple type derived is valid derived from base,
0127: * given a subset of {restriction, extension}.
0128: */
0129: public static boolean checkSimpleDerivationOk(XSSimpleType derived,
0130: XSTypeDefinition base, short block) {
0131: // if derived is anySimpleType, then it's valid only if the base
0132: // is ur-type
0133: if (derived == SchemaGrammar.fAnySimpleType) {
0134: return (base == SchemaGrammar.fAnyType || base == SchemaGrammar.fAnySimpleType);
0135: }
0136:
0137: // if base is complex type
0138: if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
0139: // if base is anyType, change base to anySimpleType,
0140: // otherwise, not valid
0141: if (base == SchemaGrammar.fAnyType)
0142: base = SchemaGrammar.fAnySimpleType;
0143: else
0144: return false;
0145: }
0146: return checkSimpleDerivation((XSSimpleType) derived,
0147: (XSSimpleType) base, block);
0148: }
0149:
0150: /**
0151: * check whether complex type derived is valid derived from base,
0152: * given a subset of {restriction, extension}.
0153: */
0154: public static boolean checkComplexDerivationOk(
0155: XSComplexTypeDecl derived, XSTypeDefinition base,
0156: short block) {
0157: // if derived is anyType, then it's valid only if base is anyType too
0158: if (derived == SchemaGrammar.fAnyType)
0159: return derived == base;
0160: return checkComplexDerivation((XSComplexTypeDecl) derived,
0161: base, block);
0162: }
0163:
0164: /**
0165: * Note: this will be a private method, and it assumes that derived is not
0166: * anySimpleType, and base is not anyType. Another method will be
0167: * introduced for public use, which will call this method.
0168: */
0169: private static boolean checkSimpleDerivation(XSSimpleType derived,
0170: XSSimpleType base, short block) {
0171: // 1 They are the same type definition.
0172: if (derived == base)
0173: return true;
0174:
0175: // 2 All of the following must be true:
0176: // 2.1 restriction is not in the subset, or in the {final} of its own {base type definition};
0177: if ((block & XSConstants.DERIVATION_RESTRICTION) != 0
0178: || (derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) {
0179: return false;
0180: }
0181:
0182: // 2.2 One of the following must be true:
0183: // 2.2.1 D's base type definition is B.
0184: XSSimpleType directBase = (XSSimpleType) derived.getBaseType();
0185: if (directBase == base)
0186: return true;
0187:
0188: // 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.
0189: if (directBase != SchemaGrammar.fAnySimpleType
0190: && checkSimpleDerivation(directBase, base, block)) {
0191: return true;
0192: }
0193:
0194: // 2.2.3 D's {variety} is list or union and B is the simple ur-type definition.
0195: if ((derived.getVariety() == XSSimpleType.VARIETY_LIST || derived
0196: .getVariety() == XSSimpleType.VARIETY_UNION)
0197: && base == SchemaGrammar.fAnySimpleType) {
0198: return true;
0199: }
0200:
0201: // 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.
0202: if (base.getVariety() == XSSimpleType.VARIETY_UNION) {
0203: XSObjectList subUnionMemberDV = base.getMemberTypes();
0204: int subUnionSize = subUnionMemberDV.getLength();
0205: for (int i = 0; i < subUnionSize; i++) {
0206: base = (XSSimpleType) subUnionMemberDV.item(i);
0207: if (checkSimpleDerivation(derived, base, block))
0208: return true;
0209: }
0210: }
0211:
0212: return false;
0213: }
0214:
0215: /**
0216: * Note: this will be a private method, and it assumes that derived is not
0217: * anyType. Another method will be introduced for public use,
0218: * which will call this method.
0219: */
0220: private static boolean checkComplexDerivation(
0221: XSComplexTypeDecl derived, XSTypeDefinition base,
0222: short block) {
0223: // 2.1 B and D must be the same type definition.
0224: if (derived == base)
0225: return true;
0226:
0227: // 1 If B and D are not the same type definition, then the {derivation method} of D must not be in the subset.
0228: if ((derived.fDerivedBy & block) != 0)
0229: return false;
0230:
0231: // 2 One of the following must be true:
0232: XSTypeDefinition directBase = derived.fBaseType;
0233: // 2.2 B must be D's {base type definition}.
0234: if (directBase == base)
0235: return true;
0236:
0237: // 2.3 All of the following must be true:
0238: // 2.3.1 D's {base type definition} must not be the ur-type definition.
0239: if (directBase == SchemaGrammar.fAnyType
0240: || directBase == SchemaGrammar.fAnySimpleType) {
0241: return false;
0242: }
0243:
0244: // 2.3.2 The appropriate case among the following must be true:
0245: // 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.
0246: if (directBase.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
0247: return checkComplexDerivation(
0248: (XSComplexTypeDecl) directBase, base, block);
0249:
0250: // 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).
0251: if (directBase.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
0252: // if base is complex type
0253: if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
0254: // if base is anyType, change base to anySimpleType,
0255: // otherwise, not valid
0256: if (base == SchemaGrammar.fAnyType)
0257: base = SchemaGrammar.fAnySimpleType;
0258: else
0259: return false;
0260: }
0261: return checkSimpleDerivation((XSSimpleType) directBase,
0262: (XSSimpleType) base, block);
0263: }
0264:
0265: return false;
0266: }
0267:
0268: /**
0269: * check whether a value is a valid default for some type
0270: * returns the compiled form of the value
0271: * The parameter value could be either a String or a ValidatedInfo object
0272: */
0273: public static Object ElementDefaultValidImmediate(
0274: XSTypeDefinition type, String value,
0275: ValidationContext context, ValidatedInfo vinfo) {
0276:
0277: XSSimpleType dv = null;
0278:
0279: // e-props-correct
0280: // For a string to be a valid default with respect to a type definition the appropriate case among the following must be true:
0281: // 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).
0282: if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
0283: dv = (XSSimpleType) type;
0284: }
0285:
0286: // 2 If the type definition is a complex type definition, then all of the following must be true:
0287: else {
0288: // 2.1 its {content type} must be a simple type definition or mixed.
0289: XSComplexTypeDecl ctype = (XSComplexTypeDecl) type;
0290: // 2.2 The appropriate case among the following must be true:
0291: // 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).
0292: if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
0293: dv = ctype.fXSSimpleType;
0294: }
0295: // 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).
0296: else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
0297: if (!((XSParticleDecl) ctype.getParticle()).emptiable())
0298: return null;
0299: } else {
0300: return null;
0301: }
0302: }
0303:
0304: // get the simple type declaration, and validate
0305: Object actualValue = null;
0306: if (dv == null) {
0307: // complex type with mixed. to make sure that we store correct
0308: // information in vinfo and return the correct value, we use
0309: // "string" type for validation
0310: dv = STRING_TYPE;
0311: }
0312: try {
0313: // validate the original lexical rep, and set the actual value
0314: actualValue = dv.validate(value, context, vinfo);
0315: // validate the canonical lexical rep
0316: if (vinfo != null)
0317: actualValue = dv.validate(vinfo.stringValue(), context,
0318: vinfo);
0319: } catch (InvalidDatatypeValueException ide) {
0320: return null;
0321: }
0322:
0323: return actualValue;
0324: }
0325:
0326: static void reportSchemaError(XMLErrorReporter errorReporter,
0327: SimpleLocator loc, String key, Object[] args) {
0328: if (loc != null) {
0329: errorReporter.reportError(loc,
0330: XSMessageFormatter.SCHEMA_DOMAIN, key, args,
0331: XMLErrorReporter.SEVERITY_ERROR);
0332: } else {
0333: errorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
0334: key, args, XMLErrorReporter.SEVERITY_ERROR);
0335: }
0336: }
0337:
0338: /**
0339: * used to check the 3 constraints against each complex type
0340: * (should be each model group):
0341: * Unique Particle Attribution, Particle Derivation (Restriction),
0342: * Element Declrations Consistent.
0343: */
0344: public static void fullSchemaChecking(
0345: XSGrammarBucket grammarBucket,
0346: SubstitutionGroupHandler SGHandler, CMBuilder cmBuilder,
0347: XMLErrorReporter errorReporter) {
0348: // get all grammars, and put all substitution group information
0349: // in the substitution group handler
0350: SchemaGrammar[] grammars = grammarBucket.getGrammars();
0351: for (int i = grammars.length - 1; i >= 0; i--) {
0352: SGHandler.addSubstitutionGroup(grammars[i]
0353: .getSubstitutionGroups());
0354: }
0355:
0356: XSParticleDecl fakeDerived = new XSParticleDecl();
0357: XSParticleDecl fakeBase = new XSParticleDecl();
0358: fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP;
0359: fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP;
0360: // before worrying about complexTypes, let's get
0361: // groups redefined by restriction out of the way.
0362: for (int g = grammars.length - 1; g >= 0; g--) {
0363: XSGroupDecl[] redefinedGroups = grammars[g]
0364: .getRedefinedGroupDecls();
0365: SimpleLocator[] rgLocators = grammars[g].getRGLocators();
0366: for (int i = 0; i < redefinedGroups.length;) {
0367: XSGroupDecl derivedGrp = redefinedGroups[i++];
0368: XSModelGroupImpl derivedMG = derivedGrp.fModelGroup;
0369: XSGroupDecl baseGrp = redefinedGroups[i++];
0370: XSModelGroupImpl baseMG = baseGrp.fModelGroup;
0371: if (baseMG == null) {
0372: if (derivedMG != null) { // can't be a restriction!
0373: reportSchemaError(errorReporter,
0374: rgLocators[i / 2 - 1],
0375: "src-redefine.6.2.2", new Object[] {
0376: derivedGrp.fName,
0377: "rcase-Recurse.2" });
0378: }
0379: } else {
0380: fakeDerived.fValue = derivedMG;
0381: fakeBase.fValue = baseMG;
0382: try {
0383: particleValidRestriction(fakeDerived,
0384: SGHandler, fakeBase, SGHandler);
0385: } catch (XMLSchemaException e) {
0386: String key = e.getKey();
0387: reportSchemaError(errorReporter,
0388: rgLocators[i / 2 - 1], key, e.getArgs());
0389: reportSchemaError(errorReporter,
0390: rgLocators[i / 2 - 1],
0391: "src-redefine.6.2.2", new Object[] {
0392: derivedGrp.fName, key });
0393: }
0394: }
0395: }
0396: }
0397:
0398: // for each complex type, check the 3 constraints.
0399: // types need to be checked
0400: XSComplexTypeDecl[] types;
0401: SimpleLocator[] ctLocators;
0402: // to hold the errors
0403: // REVISIT: do we want to report all errors? or just one?
0404: //XMLSchemaError1D errors = new XMLSchemaError1D();
0405: // whether need to check this type again;
0406: // whether only do UPA checking
0407: boolean further, fullChecked;
0408: // if do all checkings, how many need to be checked again.
0409: int keepType;
0410: // i: grammar; j: type; k: error
0411: // for all grammars
0412: SymbolHash elemTable = new SymbolHash();
0413: for (int i = grammars.length - 1, j; i >= 0; i--) {
0414: // get whether to skip EDC, and types need to be checked
0415: keepType = 0;
0416: fullChecked = grammars[i].fFullChecked;
0417: types = grammars[i].getUncheckedComplexTypeDecls();
0418: ctLocators = grammars[i].getUncheckedCTLocators();
0419: // for each type
0420: for (j = 0; j < types.length; j++) {
0421: // if we've already full-checked this grammar, then
0422: // skip the EDC constraint
0423: if (!fullChecked) {
0424: // 1. Element Decl Consistent
0425: if (types[j].fParticle != null) {
0426: elemTable.clear();
0427: try {
0428: checkElementDeclsConsistent(types[j],
0429: types[j].fParticle, elemTable,
0430: SGHandler);
0431: } catch (XMLSchemaException e) {
0432: reportSchemaError(errorReporter,
0433: ctLocators[j], e.getKey(), e
0434: .getArgs());
0435: }
0436: }
0437: }
0438:
0439: // 2. Particle Derivation
0440:
0441: if (types[j].fBaseType != null
0442: && types[j].fBaseType != SchemaGrammar.fAnyType
0443: && types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION
0444: && (types[j].fBaseType instanceof XSComplexTypeDecl)) {
0445:
0446: XSParticleDecl derivedParticle = types[j].fParticle;
0447: XSParticleDecl baseParticle = ((XSComplexTypeDecl) (types[j].fBaseType)).fParticle;
0448: if (derivedParticle == null) {
0449: if (baseParticle != null
0450: && !baseParticle.emptiable()) {
0451: reportSchemaError(errorReporter,
0452: ctLocators[j],
0453: "derivation-ok-restriction.5.3.2",
0454: new Object[] {
0455: types[j].fName,
0456: types[j].fBaseType
0457: .getName() });
0458: }
0459: } else if (baseParticle != null) {
0460: try {
0461: particleValidRestriction(
0462: types[j].fParticle,
0463: SGHandler,
0464: ((XSComplexTypeDecl) (types[j].fBaseType)).fParticle,
0465: SGHandler);
0466: } catch (XMLSchemaException e) {
0467: reportSchemaError(errorReporter,
0468: ctLocators[j], e.getKey(), e
0469: .getArgs());
0470: reportSchemaError(errorReporter,
0471: ctLocators[j],
0472: "derivation-ok-restriction.5.4.2",
0473: new Object[] { types[j].fName });
0474: }
0475: } else {
0476: reportSchemaError(errorReporter, ctLocators[j],
0477: "derivation-ok-restriction.5.4.2",
0478: new Object[] { types[j].fName });
0479: }
0480: }
0481: // 3. UPA
0482: // get the content model and check UPA
0483: XSCMValidator cm = types[j].getContentModel(cmBuilder,
0484: true);
0485: further = false;
0486: if (cm != null) {
0487: try {
0488: further = cm
0489: .checkUniqueParticleAttribution(SGHandler);
0490: } catch (XMLSchemaException e) {
0491: reportSchemaError(errorReporter, ctLocators[j],
0492: e.getKey(), e.getArgs());
0493: }
0494: }
0495: // now report all errors
0496: // REVISIT: do we want to report all errors? or just one?
0497: /*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) {
0498: reportSchemaError(errorReporter, ctLocators[j],
0499: errors.getErrorCode(k),
0500: errors.getArgs(k));
0501: }*/
0502:
0503: // if we are doing all checkings, and this one needs further
0504: // checking, store it in the type array.
0505: if (!fullChecked && further)
0506: types[keepType++] = types[j];
0507:
0508: // clear errors for the next type.
0509: // REVISIT: do we want to report all errors? or just one?
0510: //errors.clear();
0511: }
0512: // we've done with the types in this grammar. if we are checking
0513: // all constraints, need to trim type array to a proper size:
0514: // only contain those need further checking.
0515: // and mark this grammar that it only needs UPA checking.
0516: if (!fullChecked) {
0517: grammars[i].setUncheckedTypeNum(keepType);
0518: grammars[i].fFullChecked = true;
0519: }
0520: }
0521: }
0522:
0523: /*
0524: Check that a given particle is a valid restriction of a base particle.
0525: */
0526:
0527: public static void checkElementDeclsConsistent(
0528: XSComplexTypeDecl type, XSParticleDecl particle,
0529: SymbolHash elemDeclHash, SubstitutionGroupHandler sgHandler)
0530: throws XMLSchemaException {
0531:
0532: // check for elements in the tree with the same name and namespace
0533:
0534: int pType = particle.fType;
0535:
0536: if (pType == XSParticleDecl.PARTICLE_WILDCARD)
0537: return;
0538:
0539: if (pType == XSParticleDecl.PARTICLE_ELEMENT) {
0540: XSElementDecl elem = (XSElementDecl) (particle.fValue);
0541: findElemInTable(type, elem, elemDeclHash);
0542:
0543: if (elem.fScope == XSConstants.SCOPE_GLOBAL) {
0544: // Check for subsitution groups.
0545: XSElementDecl[] subGroup = sgHandler
0546: .getSubstitutionGroup(elem);
0547: for (int i = 0; i < subGroup.length; i++) {
0548: findElemInTable(type, subGroup[i], elemDeclHash);
0549: }
0550: }
0551: return;
0552: }
0553:
0554: XSModelGroupImpl group = (XSModelGroupImpl) particle.fValue;
0555: for (int i = 0; i < group.fParticleCount; i++)
0556: checkElementDeclsConsistent(type, group.fParticles[i],
0557: elemDeclHash, sgHandler);
0558: }
0559:
0560: public static void findElemInTable(XSComplexTypeDecl type,
0561: XSElementDecl elem, SymbolHash elemDeclHash)
0562: throws XMLSchemaException {
0563:
0564: // How can we avoid this concat? LM.
0565: String name = elem.fName + "," + elem.fTargetNamespace;
0566:
0567: XSElementDecl existingElem = null;
0568: if ((existingElem = (XSElementDecl) (elemDeclHash.get(name))) == null) {
0569: // just add it in
0570: elemDeclHash.put(name, elem);
0571: } else {
0572: // If this is the same check element, we're O.K.
0573: if (elem == existingElem)
0574: return;
0575:
0576: if (elem.fType != existingElem.fType) {
0577: // Types are not the same
0578: throw new XMLSchemaException("cos-element-consistent",
0579: new Object[] { type.fName, elem.fName });
0580:
0581: }
0582: }
0583: }
0584:
0585: // Check that a given particle is a valid restriction of a base particle.
0586: //
0587: // IHR: 2006/11/17
0588: // Returns a boolean indicating if there has been expansion of substitution group
0589: // in the bParticle.
0590: // With this information the checkRecurseLax function knows when is
0591: // to keep the order and when to ignore it.
0592: private static boolean particleValidRestriction(
0593: XSParticleDecl dParticle,
0594: SubstitutionGroupHandler dSGHandler,
0595: XSParticleDecl bParticle,
0596: SubstitutionGroupHandler bSGHandler)
0597: throws XMLSchemaException {
0598: return particleValidRestriction(dParticle, dSGHandler,
0599: bParticle, bSGHandler, true);
0600: }
0601:
0602: private static boolean particleValidRestriction(
0603: XSParticleDecl dParticle,
0604: SubstitutionGroupHandler dSGHandler,
0605: XSParticleDecl bParticle,
0606: SubstitutionGroupHandler bSGHandler,
0607: boolean checkWCOccurrence) throws XMLSchemaException {
0608:
0609: Vector dChildren = null;
0610: Vector bChildren = null;
0611: int dMinEffectiveTotalRange = OCCURRENCE_UNKNOWN;
0612: int dMaxEffectiveTotalRange = OCCURRENCE_UNKNOWN;
0613:
0614: // By default there has been no expansion
0615: boolean bExpansionHappened = false;
0616:
0617: // Check for empty particles. If either base or derived particle is empty,
0618: // (and the other isn't) it's an error.
0619: if (dParticle.isEmpty() && !bParticle.emptiable()) {
0620: throw new XMLSchemaException("cos-particle-restrict.a",
0621: null);
0622: } else if (!dParticle.isEmpty() && bParticle.isEmpty()) {
0623: throw new XMLSchemaException("cos-particle-restrict.b",
0624: null);
0625: }
0626:
0627: //
0628: // Do setup prior to invoking the Particle (Restriction) cases.
0629: // This involves:
0630: // - removing pointless occurrences for groups, and retrieving a vector of
0631: // non-pointless children
0632: // - turning top-level elements with substitution groups into CHOICE groups.
0633: //
0634:
0635: short dType = dParticle.fType;
0636: //
0637: // Handle pointless groups for the derived particle
0638: //
0639: if (dType == XSParticleDecl.PARTICLE_MODELGROUP) {
0640: dType = ((XSModelGroupImpl) dParticle.fValue).fCompositor;
0641:
0642: // Find a group, starting with this particle, with more than 1 child. There
0643: // may be none, and the particle of interest trivially becomes an element or
0644: // wildcard.
0645: XSParticleDecl dtmp = getNonUnaryGroup(dParticle);
0646: if (dtmp != dParticle) {
0647: // Particle has been replaced. Retrieve new type info.
0648: dParticle = dtmp;
0649: dType = dParticle.fType;
0650: if (dType == XSParticleDecl.PARTICLE_MODELGROUP)
0651: dType = ((XSModelGroupImpl) dParticle.fValue).fCompositor;
0652: }
0653:
0654: // Fill in a vector with the children of the particle, removing any
0655: // pointless model groups in the process.
0656: dChildren = removePointlessChildren(dParticle);
0657: }
0658:
0659: int dMinOccurs = dParticle.fMinOccurs;
0660: int dMaxOccurs = dParticle.fMaxOccurs;
0661:
0662: //
0663: // For elements which are the heads of substitution groups, treat as CHOICE
0664: //
0665: if (dSGHandler != null
0666: && dType == XSParticleDecl.PARTICLE_ELEMENT) {
0667: XSElementDecl dElement = (XSElementDecl) dParticle.fValue;
0668:
0669: if (dElement.fScope == XSConstants.SCOPE_GLOBAL) {
0670: // Check for subsitution groups. Treat any element that has a
0671: // subsitution group as a choice. Fill in the children vector with the
0672: // members of the substitution group
0673: XSElementDecl[] subGroup = dSGHandler
0674: .getSubstitutionGroup(dElement);
0675: if (subGroup.length > 0) {
0676: // Now, set the type to be CHOICE. The "group" will have the same
0677: // occurrence information as the original particle.
0678: dType = XSModelGroupImpl.MODELGROUP_CHOICE;
0679: dMinEffectiveTotalRange = dMinOccurs;
0680: dMaxEffectiveTotalRange = dMaxOccurs;
0681:
0682: // Fill in the vector of children
0683: dChildren = new Vector(subGroup.length + 1);
0684: for (int i = 0; i < subGroup.length; i++) {
0685: addElementToParticleVector(dChildren,
0686: subGroup[i]);
0687: }
0688: addElementToParticleVector(dChildren, dElement);
0689: Collections.sort(dChildren,
0690: ELEMENT_PARTICLE_COMPARATOR);
0691:
0692: // Set the handler to null, to indicate that we've finished handling
0693: // substitution groups for this particle.
0694: dSGHandler = null;
0695: }
0696: }
0697: }
0698:
0699: short bType = bParticle.fType;
0700: //
0701: // Handle pointless groups for the base particle
0702: //
0703: if (bType == XSParticleDecl.PARTICLE_MODELGROUP) {
0704: bType = ((XSModelGroupImpl) bParticle.fValue).fCompositor;
0705:
0706: // Find a group, starting with this particle, with more than 1 child. There
0707: // may be none, and the particle of interest trivially becomes an element or
0708: // wildcard.
0709: XSParticleDecl btmp = getNonUnaryGroup(bParticle);
0710: if (btmp != bParticle) {
0711: // Particle has been replaced. Retrieve new type info.
0712: bParticle = btmp;
0713: bType = bParticle.fType;
0714: if (bType == XSParticleDecl.PARTICLE_MODELGROUP)
0715: bType = ((XSModelGroupImpl) bParticle.fValue).fCompositor;
0716: }
0717:
0718: // Fill in a vector with the children of the particle, removing any
0719: // pointless model groups in the process.
0720: bChildren = removePointlessChildren(bParticle);
0721: }
0722:
0723: int bMinOccurs = bParticle.fMinOccurs;
0724: int bMaxOccurs = bParticle.fMaxOccurs;
0725:
0726: if (bSGHandler != null
0727: && bType == XSParticleDecl.PARTICLE_ELEMENT) {
0728: XSElementDecl bElement = (XSElementDecl) bParticle.fValue;
0729:
0730: if (bElement.fScope == XSConstants.SCOPE_GLOBAL) {
0731: // Check for subsitution groups. Treat any element that has a
0732: // subsitution group as a choice. Fill in the children vector with the
0733: // members of the substitution group
0734: XSElementDecl[] bsubGroup = bSGHandler
0735: .getSubstitutionGroup(bElement);
0736: if (bsubGroup.length > 0) {
0737: // Now, set the type to be CHOICE
0738: bType = XSModelGroupImpl.MODELGROUP_CHOICE;
0739:
0740: bChildren = new Vector(bsubGroup.length + 1);
0741: for (int i = 0; i < bsubGroup.length; i++) {
0742: addElementToParticleVector(bChildren,
0743: bsubGroup[i]);
0744: }
0745: addElementToParticleVector(bChildren, bElement);
0746: Collections.sort(bChildren,
0747: ELEMENT_PARTICLE_COMPARATOR);
0748: // Set the handler to null, to indicate that we've finished handling
0749: // substitution groups for this particle.
0750: bSGHandler = null;
0751:
0752: // if we are here expansion of bParticle happened
0753: bExpansionHappened = true;
0754: }
0755: }
0756: }
0757:
0758: //
0759: // O.K. - Figure out which particle derivation rule applies and call it
0760: //
0761: switch (dType) {
0762: case XSParticleDecl.PARTICLE_ELEMENT: {
0763: switch (bType) {
0764:
0765: // Elt:Elt NameAndTypeOK
0766: case XSParticleDecl.PARTICLE_ELEMENT: {
0767: checkNameAndTypeOK((XSElementDecl) dParticle.fValue,
0768: dMinOccurs, dMaxOccurs,
0769: (XSElementDecl) bParticle.fValue, bMinOccurs,
0770: bMaxOccurs);
0771: return bExpansionHappened;
0772: }
0773:
0774: // Elt:Any NSCompat
0775: case XSParticleDecl.PARTICLE_WILDCARD: {
0776: checkNSCompat((XSElementDecl) dParticle.fValue,
0777: dMinOccurs, dMaxOccurs,
0778: (XSWildcardDecl) bParticle.fValue, bMinOccurs,
0779: bMaxOccurs, checkWCOccurrence);
0780: return bExpansionHappened;
0781: }
0782:
0783: // Elt:All RecurseAsIfGroup
0784: case XSModelGroupImpl.MODELGROUP_CHOICE: {
0785: // Treat the element as if it were in a group of the same type
0786: // as the base Particle
0787: dChildren = new Vector();
0788: dChildren.addElement(dParticle);
0789:
0790: checkRecurseLax(dChildren, 1, 1, dSGHandler, bChildren,
0791: bMinOccurs, bMaxOccurs, bSGHandler);
0792: return bExpansionHappened;
0793: }
0794: case XSModelGroupImpl.MODELGROUP_SEQUENCE:
0795: case XSModelGroupImpl.MODELGROUP_ALL: {
0796: // Treat the element as if it were in a group of the same type
0797: // as the base Particle
0798: dChildren = new Vector();
0799: dChildren.addElement(dParticle);
0800:
0801: checkRecurse(dChildren, 1, 1, dSGHandler, bChildren,
0802: bMinOccurs, bMaxOccurs, bSGHandler);
0803: return bExpansionHappened;
0804: }
0805:
0806: default: {
0807: throw new XMLSchemaException("Internal-Error",
0808: new Object[] { "in particleValidRestriction" });
0809: }
0810: }
0811: }
0812:
0813: case XSParticleDecl.PARTICLE_WILDCARD: {
0814: switch (bType) {
0815:
0816: // Any:Any NSSubset
0817: case XSParticleDecl.PARTICLE_WILDCARD: {
0818: checkNSSubset((XSWildcardDecl) dParticle.fValue,
0819: dMinOccurs, dMaxOccurs,
0820: (XSWildcardDecl) bParticle.fValue, bMinOccurs,
0821: bMaxOccurs);
0822: return bExpansionHappened;
0823: }
0824:
0825: case XSModelGroupImpl.MODELGROUP_CHOICE:
0826: case XSModelGroupImpl.MODELGROUP_SEQUENCE:
0827: case XSModelGroupImpl.MODELGROUP_ALL:
0828: case XSParticleDecl.PARTICLE_ELEMENT: {
0829: throw new XMLSchemaException("cos-particle-restrict.2",
0830: new Object[] { "any:choice,sequence,all,elt" });
0831: }
0832:
0833: default: {
0834: throw new XMLSchemaException("Internal-Error",
0835: new Object[] { "in particleValidRestriction" });
0836: }
0837: }
0838: }
0839:
0840: case XSModelGroupImpl.MODELGROUP_ALL: {
0841: switch (bType) {
0842:
0843: // All:Any NSRecurseCheckCardinality
0844: case XSParticleDecl.PARTICLE_WILDCARD: {
0845: if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0846: dMinEffectiveTotalRange = dParticle
0847: .minEffectiveTotalRange();
0848: if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0849: dMaxEffectiveTotalRange = dParticle
0850: .maxEffectiveTotalRange();
0851:
0852: checkNSRecurseCheckCardinality(dChildren,
0853: dMinEffectiveTotalRange,
0854: dMaxEffectiveTotalRange, dSGHandler, bParticle,
0855: bMinOccurs, bMaxOccurs, checkWCOccurrence);
0856:
0857: return bExpansionHappened;
0858: }
0859:
0860: case XSModelGroupImpl.MODELGROUP_ALL: {
0861: checkRecurse(dChildren, dMinOccurs, dMaxOccurs,
0862: dSGHandler, bChildren, bMinOccurs, bMaxOccurs,
0863: bSGHandler);
0864: return bExpansionHappened;
0865: }
0866:
0867: case XSModelGroupImpl.MODELGROUP_CHOICE:
0868: case XSModelGroupImpl.MODELGROUP_SEQUENCE:
0869: case XSParticleDecl.PARTICLE_ELEMENT: {
0870: throw new XMLSchemaException("cos-particle-restrict.2",
0871: new Object[] { "all:choice,sequence,elt" });
0872: }
0873:
0874: default: {
0875: throw new XMLSchemaException("Internal-Error",
0876: new Object[] { "in particleValidRestriction" });
0877: }
0878: }
0879: }
0880:
0881: case XSModelGroupImpl.MODELGROUP_CHOICE: {
0882: switch (bType) {
0883:
0884: // Choice:Any NSRecurseCheckCardinality
0885: case XSParticleDecl.PARTICLE_WILDCARD: {
0886: if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0887: dMinEffectiveTotalRange = dParticle
0888: .minEffectiveTotalRange();
0889: if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0890: dMaxEffectiveTotalRange = dParticle
0891: .maxEffectiveTotalRange();
0892:
0893: checkNSRecurseCheckCardinality(dChildren,
0894: dMinEffectiveTotalRange,
0895: dMaxEffectiveTotalRange, dSGHandler, bParticle,
0896: bMinOccurs, bMaxOccurs, checkWCOccurrence);
0897: return bExpansionHappened;
0898: }
0899:
0900: case XSModelGroupImpl.MODELGROUP_CHOICE: {
0901: checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs,
0902: dSGHandler, bChildren, bMinOccurs, bMaxOccurs,
0903: bSGHandler);
0904: return bExpansionHappened;
0905: }
0906:
0907: case XSModelGroupImpl.MODELGROUP_ALL:
0908: case XSModelGroupImpl.MODELGROUP_SEQUENCE:
0909: case XSParticleDecl.PARTICLE_ELEMENT: {
0910: throw new XMLSchemaException("cos-particle-restrict.2",
0911: new Object[] { "choice:all,sequence,elt" });
0912: }
0913:
0914: default: {
0915: throw new XMLSchemaException("Internal-Error",
0916: new Object[] { "in particleValidRestriction" });
0917: }
0918: }
0919: }
0920:
0921: case XSModelGroupImpl.MODELGROUP_SEQUENCE: {
0922: switch (bType) {
0923:
0924: // Choice:Any NSRecurseCheckCardinality
0925: case XSParticleDecl.PARTICLE_WILDCARD: {
0926: if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0927: dMinEffectiveTotalRange = dParticle
0928: .minEffectiveTotalRange();
0929: if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
0930: dMaxEffectiveTotalRange = dParticle
0931: .maxEffectiveTotalRange();
0932:
0933: checkNSRecurseCheckCardinality(dChildren,
0934: dMinEffectiveTotalRange,
0935: dMaxEffectiveTotalRange, dSGHandler, bParticle,
0936: bMinOccurs, bMaxOccurs, checkWCOccurrence);
0937: return bExpansionHappened;
0938: }
0939:
0940: case XSModelGroupImpl.MODELGROUP_ALL: {
0941: checkRecurseUnordered(dChildren, dMinOccurs,
0942: dMaxOccurs, dSGHandler, bChildren, bMinOccurs,
0943: bMaxOccurs, bSGHandler);
0944: return bExpansionHappened;
0945: }
0946:
0947: case XSModelGroupImpl.MODELGROUP_SEQUENCE: {
0948: checkRecurse(dChildren, dMinOccurs, dMaxOccurs,
0949: dSGHandler, bChildren, bMinOccurs, bMaxOccurs,
0950: bSGHandler);
0951: return bExpansionHappened;
0952: }
0953:
0954: case XSModelGroupImpl.MODELGROUP_CHOICE: {
0955: int min1 = dMinOccurs * dChildren.size();
0956: int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) ? dMaxOccurs
0957: : dMaxOccurs * dChildren.size();
0958: checkMapAndSum(dChildren, min1, max1, dSGHandler,
0959: bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
0960: return bExpansionHappened;
0961: }
0962:
0963: case XSParticleDecl.PARTICLE_ELEMENT: {
0964: throw new XMLSchemaException("cos-particle-restrict.2",
0965: new Object[] { "seq:elt" });
0966: }
0967:
0968: default: {
0969: throw new XMLSchemaException("Internal-Error",
0970: new Object[] { "in particleValidRestriction" });
0971: }
0972: }
0973: }
0974:
0975: }
0976:
0977: return bExpansionHappened;
0978: }
0979:
0980: private static void addElementToParticleVector(Vector v,
0981: XSElementDecl d) {
0982:
0983: XSParticleDecl p = new XSParticleDecl();
0984: p.fValue = d;
0985: p.fType = XSParticleDecl.PARTICLE_ELEMENT;
0986: v.addElement(p);
0987:
0988: }
0989:
0990: private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) {
0991:
0992: if (p.fType == XSParticleDecl.PARTICLE_ELEMENT
0993: || p.fType == XSParticleDecl.PARTICLE_WILDCARD)
0994: return p;
0995:
0996: if (p.fMinOccurs == 1 && p.fMaxOccurs == 1 && p.fValue != null
0997: && ((XSModelGroupImpl) p.fValue).fParticleCount == 1)
0998: return getNonUnaryGroup(((XSModelGroupImpl) p.fValue).fParticles[0]);
0999: else
1000: return p;
1001: }
1002:
1003: private static Vector removePointlessChildren(XSParticleDecl p) {
1004:
1005: if (p.fType == XSParticleDecl.PARTICLE_ELEMENT
1006: || p.fType == XSParticleDecl.PARTICLE_WILDCARD)
1007: return null;
1008:
1009: Vector children = new Vector();
1010:
1011: XSModelGroupImpl group = (XSModelGroupImpl) p.fValue;
1012: for (int i = 0; i < group.fParticleCount; i++)
1013: gatherChildren(group.fCompositor, group.fParticles[i],
1014: children);
1015:
1016: return children;
1017: }
1018:
1019: private static void gatherChildren(int parentType,
1020: XSParticleDecl p, Vector children) {
1021:
1022: int min = p.fMinOccurs;
1023: int max = p.fMaxOccurs;
1024: int type = p.fType;
1025: if (type == XSParticleDecl.PARTICLE_MODELGROUP)
1026: type = ((XSModelGroupImpl) p.fValue).fCompositor;
1027:
1028: if (type == XSParticleDecl.PARTICLE_ELEMENT
1029: || type == XSParticleDecl.PARTICLE_WILDCARD) {
1030: children.addElement(p);
1031: return;
1032: }
1033:
1034: if (!(min == 1 && max == 1)) {
1035: children.addElement(p);
1036: } else if (parentType == type) {
1037: XSModelGroupImpl group = (XSModelGroupImpl) p.fValue;
1038: for (int i = 0; i < group.fParticleCount; i++)
1039: gatherChildren(type, group.fParticles[i], children);
1040: } else if (!p.isEmpty()) {
1041: children.addElement(p);
1042: }
1043:
1044: }
1045:
1046: private static void checkNameAndTypeOK(XSElementDecl dElement,
1047: int dMin, int dMax, XSElementDecl bElement, int bMin,
1048: int bMax) throws XMLSchemaException {
1049:
1050: //
1051: // Check that the names are the same
1052: //
1053: if (dElement.fName != bElement.fName
1054: || dElement.fTargetNamespace != bElement.fTargetNamespace) {
1055: throw new XMLSchemaException("rcase-NameAndTypeOK.1",
1056: new Object[] { dElement.fName,
1057: dElement.fTargetNamespace, bElement.fName,
1058: bElement.fTargetNamespace });
1059: }
1060:
1061: //
1062: // Check nillable
1063: //
1064: if (!bElement.getNillable() && dElement.getNillable()) {
1065: throw new XMLSchemaException("rcase-NameAndTypeOK.2",
1066: new Object[] { dElement.fName });
1067: }
1068:
1069: //
1070: // Check occurrence range
1071: //
1072: if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) {
1073: throw new XMLSchemaException(
1074: "rcase-NameAndTypeOK.3",
1075: new Object[] {
1076: dElement.fName,
1077: Integer.toString(dMin),
1078: dMax == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1079: : Integer.toString(dMax),
1080: Integer.toString(bMin),
1081: bMax == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1082: : Integer.toString(bMax) });
1083: }
1084:
1085: //
1086: // Check for consistent fixed values
1087: //
1088: if (bElement.getConstraintType() == XSConstants.VC_FIXED) {
1089: // derived one has to have a fixed value
1090: if (dElement.getConstraintType() != XSConstants.VC_FIXED) {
1091: throw new XMLSchemaException("rcase-NameAndTypeOK.4.a",
1092: new Object[] { dElement.fName,
1093: bElement.fDefault.stringValue() });
1094: }
1095:
1096: // get simple type
1097: boolean isSimple = false;
1098: if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE
1099: || ((XSComplexTypeDecl) dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
1100: isSimple = true;
1101: }
1102:
1103: // if there is no simple type, then compare based on string
1104: if (!isSimple
1105: && !bElement.fDefault.normalizedValue
1106: .equals(dElement.fDefault.normalizedValue)
1107: || isSimple
1108: && !bElement.fDefault.actualValue
1109: .equals(dElement.fDefault.actualValue)) {
1110: throw new XMLSchemaException("rcase-NameAndTypeOK.4.b",
1111: new Object[] { dElement.fName,
1112: dElement.fDefault.stringValue(),
1113: bElement.fDefault.stringValue() });
1114: }
1115: }
1116:
1117: //
1118: // Check identity constraints
1119: //
1120: checkIDConstraintRestriction(dElement, bElement);
1121:
1122: //
1123: // Check for disallowed substitutions
1124: //
1125: int blockSet1 = dElement.fBlock;
1126: int blockSet2 = bElement.fBlock;
1127: if (((blockSet1 & blockSet2) != blockSet2)
1128: || (blockSet1 == XSConstants.DERIVATION_NONE && blockSet2 != XSConstants.DERIVATION_NONE))
1129: throw new XMLSchemaException("rcase-NameAndTypeOK.6",
1130: new Object[] { dElement.fName });
1131:
1132: //
1133: // Check that the derived element's type is derived from the base's.
1134: //
1135: if (!checkTypeDerivationOk(
1136: dElement.fType,
1137: bElement.fType,
1138: (short) (XSConstants.DERIVATION_EXTENSION
1139: | XSConstants.DERIVATION_LIST | XSConstants.DERIVATION_UNION))) {
1140: throw new XMLSchemaException("rcase-NameAndTypeOK.7",
1141: new Object[] { dElement.fName,
1142: dElement.fType.getName(),
1143: bElement.fType.getName() });
1144: }
1145:
1146: }
1147:
1148: private static void checkIDConstraintRestriction(
1149: XSElementDecl derivedElemDecl, XSElementDecl baseElemDecl)
1150: throws XMLSchemaException {
1151: // TODO
1152: } // checkIDConstraintRestriction
1153:
1154: private static boolean checkOccurrenceRange(int min1, int max1,
1155: int min2, int max2) {
1156:
1157: if ((min1 >= min2)
1158: && ((max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED) || (max1 != SchemaSymbols.OCCURRENCE_UNBOUNDED && max1 <= max2)))
1159: return true;
1160: else
1161: return false;
1162: }
1163:
1164: private static void checkNSCompat(XSElementDecl elem, int min1,
1165: int max1, XSWildcardDecl wildcard, int min2, int max2,
1166: boolean checkWCOccurrence) throws XMLSchemaException {
1167:
1168: // check Occurrence ranges
1169: if (checkWCOccurrence
1170: && !checkOccurrenceRange(min1, max1, min2, max2)) {
1171: throw new XMLSchemaException(
1172: "rcase-NSCompat.2",
1173: new Object[] {
1174: elem.fName,
1175: Integer.toString(min1),
1176: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1177: : Integer.toString(max1),
1178: Integer.toString(min2),
1179: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1180: : Integer.toString(max2) });
1181: }
1182:
1183: // check wildcard allows namespace of element
1184: if (!wildcard.allowNamespace(elem.fTargetNamespace)) {
1185: throw new XMLSchemaException("rcase-NSCompat.1",
1186: new Object[] { elem.fName, elem.fTargetNamespace });
1187: }
1188:
1189: }
1190:
1191: private static void checkNSSubset(XSWildcardDecl dWildcard,
1192: int min1, int max1, XSWildcardDecl bWildcard, int min2,
1193: int max2) throws XMLSchemaException {
1194:
1195: // check Occurrence ranges
1196: if (!checkOccurrenceRange(min1, max1, min2, max2)) {
1197: throw new XMLSchemaException(
1198: "rcase-NSSubset.2",
1199: new Object[] {
1200: Integer.toString(min1),
1201: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1202: : Integer.toString(max1),
1203: Integer.toString(min2),
1204: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1205: : Integer.toString(max2) });
1206: }
1207:
1208: // check wildcard subset
1209: if (!dWildcard.isSubsetOf(bWildcard)) {
1210: throw new XMLSchemaException("rcase-NSSubset.1", null);
1211: }
1212:
1213: if (dWildcard.weakerProcessContents(bWildcard)) {
1214: throw new XMLSchemaException("rcase-NSSubset.3",
1215: new Object[] {
1216: dWildcard.getProcessContentsAsString(),
1217: bWildcard.getProcessContentsAsString() });
1218: }
1219:
1220: }
1221:
1222: private static void checkNSRecurseCheckCardinality(Vector children,
1223: int min1, int max1, SubstitutionGroupHandler dSGHandler,
1224: XSParticleDecl wildcard, int min2, int max2,
1225: boolean checkWCOccurrence) throws XMLSchemaException {
1226:
1227: // check Occurrence ranges
1228: if (checkWCOccurrence
1229: && !checkOccurrenceRange(min1, max1, min2, max2)) {
1230: throw new XMLSchemaException(
1231: "rcase-NSRecurseCheckCardinality.2",
1232: new Object[] {
1233: Integer.toString(min1),
1234: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1235: : Integer.toString(max1),
1236: Integer.toString(min2),
1237: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1238: : Integer.toString(max2) });
1239: }
1240:
1241: // Check that each member of the group is a valid restriction of the wildcard
1242: int count = children.size();
1243: try {
1244: for (int i = 0; i < count; i++) {
1245: XSParticleDecl particle1 = (XSParticleDecl) children
1246: .elementAt(i);
1247: particleValidRestriction(particle1, dSGHandler,
1248: wildcard, null, false);
1249:
1250: }
1251: }
1252: // REVISIT: should we really just ignore original cause of this error?
1253: // how can we report it?
1254: catch (XMLSchemaException e) {
1255: throw new XMLSchemaException(
1256: "rcase-NSRecurseCheckCardinality.1", null);
1257: }
1258:
1259: }
1260:
1261: private static void checkRecurse(Vector dChildren, int min1,
1262: int max1, SubstitutionGroupHandler dSGHandler,
1263: Vector bChildren, int min2, int max2,
1264: SubstitutionGroupHandler bSGHandler)
1265: throws XMLSchemaException {
1266:
1267: // check Occurrence ranges
1268: if (!checkOccurrenceRange(min1, max1, min2, max2)) {
1269: throw new XMLSchemaException(
1270: "rcase-Recurse.1",
1271: new Object[] {
1272: Integer.toString(min1),
1273: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1274: : Integer.toString(max1),
1275: Integer.toString(min2),
1276: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1277: : Integer.toString(max2) });
1278: }
1279:
1280: int count1 = dChildren.size();
1281: int count2 = bChildren.size();
1282:
1283: int current = 0;
1284: label: for (int i = 0; i < count1; i++) {
1285:
1286: XSParticleDecl particle1 = (XSParticleDecl) dChildren
1287: .elementAt(i);
1288: for (int j = current; j < count2; j++) {
1289: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1290: .elementAt(j);
1291: current += 1;
1292: try {
1293: particleValidRestriction(particle1, dSGHandler,
1294: particle2, bSGHandler);
1295: continue label;
1296: } catch (XMLSchemaException e) {
1297: if (!particle2.emptiable())
1298: throw new XMLSchemaException("rcase-Recurse.2",
1299: null);
1300: }
1301: }
1302: throw new XMLSchemaException("rcase-Recurse.2", null);
1303: }
1304:
1305: // Now, see if there are some elements in the base we didn't match up
1306: for (int j = current; j < count2; j++) {
1307: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1308: .elementAt(j);
1309: if (!particle2.emptiable()) {
1310: throw new XMLSchemaException("rcase-Recurse.2", null);
1311: }
1312: }
1313:
1314: }
1315:
1316: private static void checkRecurseUnordered(Vector dChildren,
1317: int min1, int max1, SubstitutionGroupHandler dSGHandler,
1318: Vector bChildren, int min2, int max2,
1319: SubstitutionGroupHandler bSGHandler)
1320: throws XMLSchemaException {
1321:
1322: // check Occurrence ranges
1323: if (!checkOccurrenceRange(min1, max1, min2, max2)) {
1324: throw new XMLSchemaException(
1325: "rcase-RecurseUnordered.1",
1326: new Object[] {
1327: Integer.toString(min1),
1328: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1329: : Integer.toString(max1),
1330: Integer.toString(min2),
1331: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1332: : Integer.toString(max2) });
1333: }
1334:
1335: int count1 = dChildren.size();
1336: int count2 = bChildren.size();
1337:
1338: boolean foundIt[] = new boolean[count2];
1339:
1340: label: for (int i = 0; i < count1; i++) {
1341: XSParticleDecl particle1 = (XSParticleDecl) dChildren
1342: .elementAt(i);
1343:
1344: for (int j = 0; j < count2; j++) {
1345: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1346: .elementAt(j);
1347: try {
1348: particleValidRestriction(particle1, dSGHandler,
1349: particle2, bSGHandler);
1350: if (foundIt[j])
1351: throw new XMLSchemaException(
1352: "rcase-RecurseUnordered.2", null);
1353: else
1354: foundIt[j] = true;
1355:
1356: continue label;
1357: } catch (XMLSchemaException e) {
1358: }
1359: }
1360: // didn't find a match. Detect an error
1361: throw new XMLSchemaException("rcase-RecurseUnordered.2",
1362: null);
1363: }
1364:
1365: // Now, see if there are some elements in the base we didn't match up
1366: for (int j = 0; j < count2; j++) {
1367: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1368: .elementAt(j);
1369: if (!foundIt[j] && !particle2.emptiable()) {
1370: throw new XMLSchemaException(
1371: "rcase-RecurseUnordered.2", null);
1372: }
1373: }
1374:
1375: }
1376:
1377: private static void checkRecurseLax(Vector dChildren, int min1,
1378: int max1, SubstitutionGroupHandler dSGHandler,
1379: Vector bChildren, int min2, int max2,
1380: SubstitutionGroupHandler bSGHandler)
1381: throws XMLSchemaException {
1382:
1383: // check Occurrence ranges
1384: if (!checkOccurrenceRange(min1, max1, min2, max2)) {
1385: throw new XMLSchemaException(
1386: "rcase-RecurseLax.1",
1387: new Object[] {
1388: Integer.toString(min1),
1389: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1390: : Integer.toString(max1),
1391: Integer.toString(min2),
1392: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1393: : Integer.toString(max2) });
1394: }
1395:
1396: int count1 = dChildren.size();
1397: int count2 = bChildren.size();
1398:
1399: int current = 0;
1400: label: for (int i = 0; i < count1; i++) {
1401:
1402: XSParticleDecl particle1 = (XSParticleDecl) dChildren
1403: .elementAt(i);
1404: for (int j = current; j < count2; j++) {
1405: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1406: .elementAt(j);
1407: current += 1;
1408: try {
1409: // IHR: go back one element on b list because the next element may match
1410: // this as well.
1411: if (particleValidRestriction(particle1, dSGHandler,
1412: particle2, bSGHandler))
1413: current--;
1414: continue label;
1415: } catch (XMLSchemaException e) {
1416: }
1417: }
1418: // didn't find a match. Detect an error
1419: throw new XMLSchemaException("rcase-RecurseLax.2", null);
1420:
1421: }
1422:
1423: }
1424:
1425: private static void checkMapAndSum(Vector dChildren, int min1,
1426: int max1, SubstitutionGroupHandler dSGHandler,
1427: Vector bChildren, int min2, int max2,
1428: SubstitutionGroupHandler bSGHandler)
1429: throws XMLSchemaException {
1430:
1431: // See if the sequence group is a valid restriction of the choice
1432:
1433: // Here is an example of a valid restriction:
1434: // <choice minOccurs="2">
1435: // <a/>
1436: // <b/>
1437: // <c/>
1438: // </choice>
1439: //
1440: // <sequence>
1441: // <b/>
1442: // <a/>
1443: // </sequence>
1444:
1445: // check Occurrence ranges
1446: if (!checkOccurrenceRange(min1, max1, min2, max2)) {
1447: throw new XMLSchemaException(
1448: "rcase-MapAndSum.2",
1449: new Object[] {
1450: Integer.toString(min1),
1451: max1 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1452: : Integer.toString(max1),
1453: Integer.toString(min2),
1454: max2 == SchemaSymbols.OCCURRENCE_UNBOUNDED ? "unbounded"
1455: : Integer.toString(max2) });
1456: }
1457:
1458: int count1 = dChildren.size();
1459: int count2 = bChildren.size();
1460:
1461: label: for (int i = 0; i < count1; i++) {
1462:
1463: XSParticleDecl particle1 = (XSParticleDecl) dChildren
1464: .elementAt(i);
1465: for (int j = 0; j < count2; j++) {
1466: XSParticleDecl particle2 = (XSParticleDecl) bChildren
1467: .elementAt(j);
1468: try {
1469: particleValidRestriction(particle1, dSGHandler,
1470: particle2, bSGHandler);
1471: continue label;
1472: } catch (XMLSchemaException e) {
1473: }
1474: }
1475: // didn't find a match. Detect an error
1476: throw new XMLSchemaException("rcase-MapAndSum.1", null);
1477: }
1478: }
1479:
1480: // to check whether two element overlap, as defined in constraint UPA
1481: public static boolean overlapUPA(XSElementDecl element1,
1482: XSElementDecl element2, SubstitutionGroupHandler sgHandler) {
1483: // if the two element have the same name and namespace,
1484: if (element1.fName == element2.fName
1485: && element1.fTargetNamespace == element2.fTargetNamespace) {
1486: return true;
1487: }
1488:
1489: // or if there is an element decl in element1's substitution group,
1490: // who has the same name/namespace with element2
1491: XSElementDecl[] subGroup = sgHandler
1492: .getSubstitutionGroup(element1);
1493: for (int i = subGroup.length - 1; i >= 0; i--) {
1494: if (subGroup[i].fName == element2.fName
1495: && subGroup[i].fTargetNamespace == element2.fTargetNamespace) {
1496: return true;
1497: }
1498: }
1499:
1500: // or if there is an element decl in element2's substitution group,
1501: // who has the same name/namespace with element1
1502: subGroup = sgHandler.getSubstitutionGroup(element2);
1503: for (int i = subGroup.length - 1; i >= 0; i--) {
1504: if (subGroup[i].fName == element1.fName
1505: && subGroup[i].fTargetNamespace == element1.fTargetNamespace) {
1506: return true;
1507: }
1508: }
1509:
1510: return false;
1511: }
1512:
1513: // to check whether an element overlaps with a wildcard,
1514: // as defined in constraint UPA
1515: public static boolean overlapUPA(XSElementDecl element,
1516: XSWildcardDecl wildcard, SubstitutionGroupHandler sgHandler) {
1517: // if the wildcard allows the element
1518: if (wildcard.allowNamespace(element.fTargetNamespace))
1519: return true;
1520:
1521: // or if the wildcard allows any element in the substitution group
1522: XSElementDecl[] subGroup = sgHandler
1523: .getSubstitutionGroup(element);
1524: for (int i = subGroup.length - 1; i >= 0; i--) {
1525: if (wildcard.allowNamespace(subGroup[i].fTargetNamespace))
1526: return true;
1527: }
1528:
1529: return false;
1530: }
1531:
1532: public static boolean overlapUPA(XSWildcardDecl wildcard1,
1533: XSWildcardDecl wildcard2) {
1534: // if the intersection of the two wildcard is not empty list
1535: XSWildcardDecl intersect = wildcard1.performIntersectionWith(
1536: wildcard2, wildcard1.fProcessContents);
1537: if (intersect == null
1538: || intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST
1539: || intersect.fNamespaceList.length != 0) {
1540: return true;
1541: }
1542:
1543: return false;
1544: }
1545:
1546: // call one of the above methods according to the type of decls
1547: public static boolean overlapUPA(Object decl1, Object decl2,
1548: SubstitutionGroupHandler sgHandler) {
1549: if (decl1 instanceof XSElementDecl) {
1550: if (decl2 instanceof XSElementDecl) {
1551: return overlapUPA((XSElementDecl) decl1,
1552: (XSElementDecl) decl2, sgHandler);
1553: } else {
1554: return overlapUPA((XSElementDecl) decl1,
1555: (XSWildcardDecl) decl2, sgHandler);
1556: }
1557: } else {
1558: if (decl2 instanceof XSElementDecl) {
1559: return overlapUPA((XSElementDecl) decl2,
1560: (XSWildcardDecl) decl1, sgHandler);
1561: } else {
1562: return overlapUPA((XSWildcardDecl) decl1,
1563: (XSWildcardDecl) decl2);
1564: }
1565: }
1566: }
1567:
1568: } // class XSContraints
|