286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 2001-2005 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A
286N/Apackage com.sun.org.apache.xerces.internal.impl.xs;
286N/A
286N/Aimport com.sun.org.apache.xerces.internal.xs.XSConstants;
286N/Aimport com.sun.org.apache.xerces.internal.xs.XSObjectList;
286N/Aimport com.sun.org.apache.xerces.internal.xs.XSSimpleTypeDefinition;
286N/Aimport com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
286N/Aimport com.sun.org.apache.xerces.internal.xni.QName;
286N/Aimport java.util.Hashtable;
286N/Aimport java.util.Vector;
286N/A
286N/A/**
286N/A * To store and validate information about substitutionGroup
286N/A *
286N/A * @xerces.internal
286N/A *
286N/A * @author Sandy Gao, IBM
286N/A *
286N/A * @version $Id: SubstitutionGroupHandler.java,v 1.6 2010-11-01 04:39:55 joehw Exp $
286N/A */
286N/Apublic class SubstitutionGroupHandler {
286N/A
286N/A private static final XSElementDecl[] EMPTY_GROUP = new XSElementDecl[0];
286N/A
286N/A // grammar resolver
286N/A XSGrammarBucket fGrammarBucket;
286N/A
286N/A /**
286N/A * Default constructor
286N/A */
286N/A public SubstitutionGroupHandler(XSGrammarBucket grammarBucket) {
286N/A fGrammarBucket = grammarBucket;
286N/A }
286N/A
286N/A // 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3
286N/A // check whether one element decl matches an element with the given qname
286N/A public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) {
286N/A if (element.localpart == exemplar.fName &&
286N/A element.uri == exemplar.fTargetNamespace) {
286N/A return exemplar;
286N/A }
286N/A
286N/A // if the exemplar is not a global element decl, then it's not possible
286N/A // to be substituted by another element.
286N/A if (exemplar.fScope != XSConstants.SCOPE_GLOBAL)
286N/A return null;
286N/A
286N/A // if the decl blocks substitution, return false
286N/A if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0)
286N/A return null;
286N/A
286N/A // get grammar of the element
286N/A SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri);
286N/A if (sGrammar == null)
286N/A return null;
286N/A
286N/A // get the decl for the element
286N/A XSElementDecl eDecl = sGrammar.getGlobalElementDecl(element.localpart);
286N/A if (eDecl == null)
286N/A return null;
286N/A
286N/A // and check by using substitutionGroup information
286N/A if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock))
286N/A return eDecl;
286N/A
286N/A return null;
286N/A }
286N/A
286N/A // 3.3.6 Substitution Group OK (Transitive)
286N/A // check whether element can substitute exemplar
286N/A protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) {
286N/A // For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true:
286N/A // 1. D and C are the same element declaration.
286N/A if (element == exemplar)
286N/A return true;
286N/A
286N/A // 2 All of the following must be true:
286N/A // 2.1 The blocking constraint does not contain substitution.
286N/A if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0)
286N/A return false;
286N/A
286N/A // 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . .
286N/A XSElementDecl subGroup = element.fSubGroup;
286N/A while (subGroup != null && subGroup != exemplar) {
286N/A subGroup = subGroup.fSubGroup;
286N/A }
286N/A
286N/A if (subGroup == null)
286N/A return false;
286N/A
286N/A // 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}.
286N/A // prepare the combination of {derivation method} and
286N/A // {disallowed substitution}
286N/A return typeDerivationOK(element.fType, exemplar.fType, blockingConstraint);
286N/A }
286N/A private boolean typeDerivationOK(XSTypeDefinition derived, XSTypeDefinition base, short blockingConstraint) {
286N/A
286N/A short devMethod = 0, blockConstraint = blockingConstraint;
286N/A
286N/A // "derived" should be derived from "base"
286N/A // add derivation methods of derived types to devMethod;
286N/A // add block of base types to blockConstraint.
286N/A XSTypeDefinition type = derived;
286N/A while (type != base && type != SchemaGrammar.fAnyType) {
286N/A if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
286N/A devMethod |= ((XSComplexTypeDecl)type).fDerivedBy;
286N/A }
286N/A else {
286N/A devMethod |= XSConstants.DERIVATION_RESTRICTION;
286N/A }
286N/A type = type.getBaseType();
286N/A // type == null means the current type is anySimpleType,
286N/A // whose base type should be anyType
286N/A if (type == null) {
286N/A type = SchemaGrammar.fAnyType;
286N/A }
286N/A if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
286N/A blockConstraint |= ((XSComplexTypeDecl)type).fBlock;
286N/A }
286N/A }
286N/A if (type != base) {
286N/A // If the base is a union, check if "derived" is allowed through any of the member types.
286N/A if (base.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
286N/A XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) base;
286N/A if (st.getVariety() == XSSimpleTypeDefinition.VARIETY_UNION) {
286N/A XSObjectList memberTypes = st.getMemberTypes();
286N/A final int length = memberTypes.getLength();
286N/A for (int i = 0; i < length; ++i) {
286N/A if (typeDerivationOK(derived, (XSTypeDefinition) memberTypes.item(i), blockingConstraint)) {
286N/A return true;
286N/A }
286N/A }
286N/A }
286N/A }
286N/A return false;
286N/A }
286N/A if ((devMethod & blockConstraint) != 0) {
286N/A return false;
286N/A }
286N/A return true;
286N/A }
286N/A
286N/A // check whether element is in exemplar's substitution group
286N/A public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) {
286N/A // [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows:
286N/A // Define PSG, the potential substitution group for HEAD, as follows:
286N/A // 1 The element declaration itself is in PSG;
286N/A // 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself.
286N/A // HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true:
286N/A // 1 Its {abstract} is false.
286N/A // 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6).
286N/A return substitutionGroupOK(element, exemplar, exemplar.fBlock);
286N/A }
286N/A
286N/A // to store substitution group information
286N/A // the key to the hashtable is an element decl, and the value is
286N/A // - a Vector, which contains all elements that has this element as their
286N/A // substitution group affilication
286N/A // - an array of OneSubGroup, which contains its substitution group before block.
286N/A Hashtable fSubGroupsB = new Hashtable();
286N/A private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0];
286N/A // The real substitution groups (after "block")
286N/A Hashtable fSubGroups = new Hashtable();
286N/A
286N/A /**
286N/A * clear the internal registry of substitutionGroup information
286N/A */
286N/A public void reset() {
286N/A fSubGroupsB.clear();
286N/A fSubGroups.clear();
286N/A }
286N/A
286N/A /**
286N/A * add a list of substitution group information.
286N/A */
286N/A public void addSubstitutionGroup(XSElementDecl[] elements) {
286N/A XSElementDecl subHead, element;
286N/A Vector subGroup;
286N/A // for all elements with substitution group affiliation
286N/A for (int i = elements.length-1; i >= 0; i--) {
286N/A element = elements[i];
286N/A subHead = element.fSubGroup;
286N/A // check whether this an entry for this element
286N/A subGroup = (Vector)fSubGroupsB.get(subHead);
286N/A if (subGroup == null) {
286N/A // if not, create a new one
286N/A subGroup = new Vector();
286N/A fSubGroupsB.put(subHead, subGroup);
286N/A }
286N/A // add to the vactor
286N/A subGroup.addElement(element);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * get all elements that can substitute the given element,
286N/A * according to the spec, we shouldn't consider the {block} constraints.
286N/A *
286N/A * from the spec, substitution group of a given element decl also contains
286N/A * the element itself. but the array returned from this method doesn't
286N/A * containt this element.
286N/A */
286N/A public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) {
286N/A // If we already have sub group for this element, just return it.
286N/A Object subGroup = fSubGroups.get(element);
286N/A if (subGroup != null)
286N/A return (XSElementDecl[])subGroup;
286N/A
286N/A if ((element.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) {
286N/A fSubGroups.put(element, EMPTY_GROUP);
286N/A return EMPTY_GROUP;
286N/A }
286N/A
286N/A // Otherwise, get all potential sub group elements
286N/A // (without considering "block" on this element
286N/A OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup());
286N/A int len = groupB.length, rlen = 0;
286N/A XSElementDecl[] ret = new XSElementDecl[len];
286N/A // For each of such elements, check whether the derivation methods
286N/A // overlap with "block". If not, add it to the sub group
286N/A for (int i = 0 ; i < len; i++) {
286N/A if ((element.fBlock & groupB[i].dMethod) == 0)
286N/A ret[rlen++] = groupB[i].sub;
286N/A }
286N/A // Resize the array if necessary
286N/A if (rlen < len) {
286N/A XSElementDecl[] ret1 = new XSElementDecl[rlen];
286N/A System.arraycopy(ret, 0, ret1, 0, rlen);
286N/A ret = ret1;
286N/A }
286N/A // Store the subgroup
286N/A fSubGroups.put(element, ret);
286N/A
286N/A return ret;
286N/A }
286N/A
286N/A // Get potential sub group element (without considering "block")
286N/A private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) {
286N/A Object subGroup = fSubGroupsB.get(element);
286N/A
286N/A // substitution group for this one is empty
286N/A if (subGroup == null) {
286N/A fSubGroupsB.put(element, EMPTY_VECTOR);
286N/A return EMPTY_VECTOR;
286N/A }
286N/A
286N/A // we've already calculated the element, just return.
286N/A if (subGroup instanceof OneSubGroup[])
286N/A return (OneSubGroup[])subGroup;
286N/A
286N/A // we only have the *direct* substitutions
286N/A Vector group = (Vector)subGroup, newGroup = new Vector();
286N/A OneSubGroup[] group1;
286N/A // then for each of the direct substitutions, get its substitution
286N/A // group, and combine the groups together.
286N/A short dMethod, bMethod, dSubMethod, bSubMethod;
286N/A for (int i = group.size()-1, j; i >= 0; i--) {
286N/A // Check whether this element is blocked. If so, ignore it.
286N/A XSElementDecl sub = (XSElementDecl)group.elementAt(i);
286N/A if (!getDBMethods(sub.fType, element.fType, methods))
286N/A continue;
286N/A // Remember derivation methods and blocks from the types
286N/A dMethod = methods.dMethod;
286N/A bMethod = methods.bMethod;
286N/A // Add this one to potential group
286N/A newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod));
286N/A // Get potential group for this element
286N/A group1 = getSubGroupB(sub, methods);
286N/A for (j = group1.length-1; j >= 0; j--) {
286N/A // For each of them, check whether it's blocked (by type)
286N/A dSubMethod = (short)(dMethod | group1[j].dMethod);
286N/A bSubMethod = (short)(bMethod | group1[j].bMethod);
286N/A // Ignore it if it's blocked
286N/A if ((dSubMethod & bSubMethod) != 0)
286N/A continue;
286N/A newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod));
286N/A }
286N/A }
286N/A // Convert to an array
286N/A OneSubGroup[] ret = new OneSubGroup[newGroup.size()];
286N/A for (int i = newGroup.size()-1; i >= 0; i--) {
286N/A ret[i] = (OneSubGroup)newGroup.elementAt(i);
286N/A }
286N/A // Store the potential sub group
286N/A fSubGroupsB.put(element, ret);
286N/A
286N/A return ret;
286N/A }
286N/A
286N/A private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb,
286N/A OneSubGroup methods) {
286N/A short dMethod = 0, bMethod = 0;
286N/A while (typed != typeb && typed != SchemaGrammar.fAnyType) {
286N/A if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
286N/A dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy;
286N/A else
286N/A dMethod |= XSConstants.DERIVATION_RESTRICTION;
286N/A typed = typed.getBaseType();
286N/A // type == null means the current type is anySimpleType,
286N/A // whose base type should be anyType
286N/A if (typed == null)
286N/A typed = SchemaGrammar.fAnyType;
286N/A if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
286N/A bMethod |= ((XSComplexTypeDecl)typed).fBlock;
286N/A }
286N/A // No derivation relation, or blocked, return false
286N/A if (typed != typeb || (dMethod & bMethod) != 0)
286N/A return false;
286N/A
286N/A // Remember the derivation methods and blocks, return true.
286N/A methods.dMethod = dMethod;
286N/A methods.bMethod = bMethod;
286N/A return true;
286N/A }
286N/A
286N/A // Record the information about how one element substitute another one
286N/A private static final class OneSubGroup {
286N/A OneSubGroup() {}
286N/A OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) {
286N/A this.sub = sub;
286N/A this.dMethod = dMethod;
286N/A this.bMethod = bMethod;
286N/A }
286N/A // The element that substitutes another one
286N/A XSElementDecl sub;
286N/A // The combination of all derivation methods from sub's type to
286N/A // the head's type
286N/A short dMethod;
286N/A // The combination of {block} of the types in the derivation chain
286N/A // excluding sub's type
286N/A short bMethod;
286N/A }
286N/A} // class SubstitutionGroupHandler