001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 2000 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057: package org.apache.xerces.validators.schema;
058:
059: import org.apache.xerces.utils.QName;
060: import org.apache.xerces.utils.StringPool;
061: import org.apache.xerces.validators.common.GrammarResolver;
062: import org.apache.xerces.validators.common.XMLElementDecl;
063: import org.apache.xerces.validators.datatype.DatatypeValidator;
064:
065: import org.xml.sax.SAXException;
066: import org.apache.xerces.framework.XMLErrorReporter;
067: import org.apache.xerces.utils.XMLMessages;
068:
069: import java.lang.ClassCastException;
070: import java.util.Vector;
071:
072: /*
073: * @version 1.0. ericye, neilg
074: *
075: * Modified by neilg, 01/18/01
076: * Note: this class, formerly called equivClassComparator.java, has
077: * been renamed to comply with schema CR changes. It still contains
078: * some outmoded terminology--such as use of the term "exemplar", now
079: * referred to as the head of the substitution group. I have
080: * changed as much terminology as possible, but I thought future
081: * maintainers could deal with simple and not necessarily-ill-named
082: * concepts like exemplar.
083: */
084:
085: public class SubstitutionGroupComparator {
086:
087: // constants
088: private final int TOP_LEVEL_SCOPE = -1;
089:
090: // private data members
091: private StringPool fStringPool = null;
092: private GrammarResolver fGrammarResolver = null;
093: private XMLErrorReporter fErrorReporter = null;
094:
095: // constructors
096: private SubstitutionGroupComparator() {
097: // can never be instantiated without passing in a GrammarResolver.
098: }
099:
100: public SubstitutionGroupComparator(GrammarResolver grammarResolver,
101: StringPool stringPool, XMLErrorReporter errorReporter) {
102: fGrammarResolver = grammarResolver;
103: fStringPool = stringPool;
104: fErrorReporter = errorReporter;
105: }
106:
107: public StringPool getStringPool() {
108: return fStringPool;
109: }
110:
111: public XMLErrorReporter getErrorReporter() {
112: return fErrorReporter;
113: }
114:
115: //public methods
116: public boolean isEquivalentTo(QName anElement, QName exemplar)
117: throws Exception {
118: if (anElement.localpart == exemplar.localpart
119: && anElement.uri == exemplar.uri) {
120: return true; // they're the same!
121: }
122:
123: if (fGrammarResolver == null || fStringPool == null) {
124: throw new SAXException(
125: "Internal error; tried to check an element against a substitutionGroup, but no GrammarResolver is defined");
126: }
127:
128: // ??? TODO: first try to use
129: // sGrammar.getElementDeclAllSubstitutionGroupQNames();
130: // which should save lots of time
131:
132: int uriIndex = anElement.uri;
133: int localpartIndex = anElement.localpart;
134: String uri = fStringPool.toString(anElement.uri);
135: String localpart = fStringPool.toString(anElement.localpart);
136:
137: // In addition to simply trying to find a chain between anElement and exemplar,
138: // we need to make sure that no steps in the chain are blocked.
139: // That is, at every step, we need to make sure that the element
140: // being substituted for will permit being substituted
141: // for, and whether the type of the element will permit derivations in
142: // instance documents of this sort.
143: if (uri == null) {
144: return false;
145: }
146: SchemaGrammar sGrammar = null;
147: try {
148: sGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(uri);
149: } catch (ClassCastException ce) {
150: //since the return Grammar is not a SchemaGrammar, bail out
151: String er = "Grammar with URI " + uri
152: + " is not a schema grammar!";
153: Object[] a = { er };
154: fErrorReporter.reportError(fErrorReporter.getLocator(),
155: XMLMessages.XML_DOMAIN,
156: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
157: XMLMessages.SCHEMA_GENERIC_ERROR, a,
158: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
159: return false;
160: }
161: if (sGrammar == null) {
162: return false;
163: }
164:
165: // this will be the index of anElement
166: int elementIndex = sGrammar.getElementDeclIndex(uriIndex,
167: localpartIndex, TOP_LEVEL_SCOPE);
168: int anElementIndex = elementIndex;
169:
170: String substitutionGroupFullName = sGrammar
171: .getElementDeclSubstitutionGroupAffFullName(elementIndex);
172: boolean foundIt = false;
173: while (substitutionGroupFullName != null) {
174: int commaAt = substitutionGroupFullName.indexOf(",");
175: uri = "";
176: localpart = substitutionGroupFullName;
177: if (commaAt >= 0) {
178: if (commaAt > 0) {
179: uri = substitutionGroupFullName.substring(0,
180: commaAt);
181: }
182: localpart = substitutionGroupFullName
183: .substring(commaAt + 1);
184: }
185: if (uri == null) {
186: return false;
187: }
188: try {
189: sGrammar = (SchemaGrammar) fGrammarResolver
190: .getGrammar(uri);
191: } catch (ClassCastException ce) {
192: //since the return Grammar is not a SchemaGrammar, bail out
193: String er = "Grammar with URI " + uri
194: + " is not a schema grammar!";
195: Object[] a = { er };
196: fErrorReporter.reportError(fErrorReporter.getLocator(),
197: XMLMessages.XML_DOMAIN,
198: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
199: XMLMessages.SCHEMA_GENERIC_ERROR, a,
200: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
201: return false;
202: }
203: if (sGrammar == null) {
204: return false;
205: }
206: uriIndex = fStringPool.addSymbol(uri);
207: localpartIndex = fStringPool.addSymbol(localpart);
208: elementIndex = sGrammar.getElementDeclIndex(uriIndex,
209: localpartIndex, TOP_LEVEL_SCOPE);
210: if (elementIndex == -1) {
211: return false;
212: }
213:
214: if (uriIndex == exemplar.uri
215: && localpartIndex == exemplar.localpart) {
216: // time to check for block value on element
217: if ((sGrammar.getElementDeclBlockSet(elementIndex) & SchemaSymbols.SUBSTITUTION) != 0) {
218: return false;
219: }
220: foundIt = true;
221: break;
222: }
223:
224: substitutionGroupFullName = sGrammar
225: .getElementDeclSubstitutionGroupAffFullName(elementIndex);
226:
227: }
228:
229: if (!foundIt) {
230: return false;
231: }
232: // this will contain anElement's complexType information.
233: TraverseSchema.ComplexTypeInfo aComplexType = sGrammar
234: .getElementComplexTypeInfo(anElementIndex);
235: // elementIndex contains the index of the substitutionGroup head
236: int exemplarBlockSet = sGrammar
237: .getElementDeclBlockSet(elementIndex);
238: if (aComplexType == null) {
239: // check on simpleType case
240: XMLElementDecl anElementDecl = new XMLElementDecl();
241: sGrammar.getElementDecl(anElementIndex, anElementDecl);
242: DatatypeValidator anElementDV = anElementDecl.datatypeValidator;
243: XMLElementDecl exemplarDecl = new XMLElementDecl();
244: sGrammar.getElementDecl(elementIndex, exemplarDecl);
245: DatatypeValidator exemplarDV = exemplarDecl.datatypeValidator;
246: return ((anElementDV == null) || ((anElementDV == exemplarDV) || ((exemplarBlockSet & SchemaSymbols.RESTRICTION) == 0)));
247: }
248: // now we have to make sure there are no blocks on the complexTypes that this is based upon
249: int anElementDerivationMethod = aComplexType.derivedBy;
250: if ((anElementDerivationMethod & exemplarBlockSet) != 0)
251: return false;
252: // this will contain exemplar's complexType information.
253: TraverseSchema.ComplexTypeInfo exemplarComplexType = sGrammar
254: .getElementComplexTypeInfo(elementIndex);
255: for (TraverseSchema.ComplexTypeInfo tempType = aComplexType; tempType != null
256: && tempType != exemplarComplexType; tempType = tempType.baseComplexTypeInfo) {
257: if ((tempType.blockSet & anElementDerivationMethod) != 0) {
258: return false;
259: }
260: }
261: return true;
262: }
263:
264: /**
265: * check whether one element or any element in its substitution group
266: * is allowed by a given wildcard uri
267: *
268: * @param element the QName of a given element
269: * @param wuri the uri of the wildcard
270: * @param wother whether the uri is from ##other, so wuri is excluded
271: *
272: * @return whether the element is allowed by the wildcard
273: */
274: public boolean isAllowedByWildcard(QName element, int wuri,
275: boolean wother) throws Exception {
276: // whether the uri is allowed directly by the wildcard
277: if (!wother && element.uri == wuri ||
278: //wother && element.uri != wuri && element.uri != fStringPool.EMPTY_STRING) { // ??? TODO
279: wother && element.uri != wuri) {
280: return true;
281: }
282:
283: if (fGrammarResolver == null || fStringPool == null) {
284: throw new SAXException(
285: "Internal error; tried to check an element against a substitutionGroup, but no GrammarResolver is defined");
286: }
287:
288: // get the corresponding grammar
289: String uri = fStringPool.toString(element.uri);
290: if (uri == null)
291: return false;
292: SchemaGrammar sGrammar = null;
293: try {
294: sGrammar = (SchemaGrammar) fGrammarResolver.getGrammar(uri);
295: } catch (ClassCastException ce) {
296: //since the return Grammar is not a SchemaGrammar, bail out
297: String er = "Grammar with URI " + uri
298: + " is not a schema grammar!";
299: Object[] a = { er };
300: fErrorReporter.reportError(fErrorReporter.getLocator(),
301: XMLMessages.XML_DOMAIN,
302: XMLMessages.MSG_GENERIC_SCHEMA_ERROR,
303: XMLMessages.SCHEMA_GENERIC_ERROR, a,
304: XMLErrorReporter.ERRORTYPE_RECOVERABLE_ERROR);
305: return false;
306: }
307: if (sGrammar == null)
308: return false;
309:
310: // then get the element decl index for the element
311: int elementIndex = sGrammar.getElementDeclIndex(element,
312: TOP_LEVEL_SCOPE);
313:
314: // get all elements that can substitute the current element
315: Vector substitutionGroupQNames = sGrammar
316: .getElementDeclAllSubstitutionGroupQNames(elementIndex,
317: fGrammarResolver, fStringPool);
318:
319: // then check whether there exists one elemet that is allowed by the wildcard
320: int size = substitutionGroupQNames == null ? 0
321: : substitutionGroupQNames.size();
322: for (int i = 0; i < size; i++) {
323: QName name = ((SchemaGrammar.OneSubGroup) substitutionGroupQNames
324: .elementAt(i)).name;
325: if (!wother && name.uri == wuri ||
326: //wother && name.uri != wuri && name.uri != fStringPool.EMPTY_STRING) { // ??? TODO
327: wother && name.uri != wuri) {
328: return true;
329: }
330: }
331:
332: return false;
333: }
334: }
|