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.traversers;
0019:
0020: import java.io.IOException;
0021: import java.io.StringReader;
0022: import java.util.ArrayList;
0023: import java.util.Hashtable;
0024: import java.util.Stack;
0025: import java.util.Vector;
0026:
0027: import org.apache.xerces.impl.Constants;
0028: import org.apache.xerces.impl.XMLEntityManager;
0029: import org.apache.xerces.impl.XMLErrorReporter;
0030: import org.apache.xerces.impl.xs.SchemaGrammar;
0031: import org.apache.xerces.impl.xs.SchemaNamespaceSupport;
0032: import org.apache.xerces.impl.xs.SchemaSymbols;
0033: import org.apache.xerces.impl.xs.XMLSchemaException;
0034: import org.apache.xerces.impl.xs.XMLSchemaLoader;
0035: import org.apache.xerces.impl.xs.XSComplexTypeDecl;
0036: import org.apache.xerces.impl.xs.XSDDescription;
0037: import org.apache.xerces.impl.xs.XSDeclarationPool;
0038: import org.apache.xerces.impl.xs.XSElementDecl;
0039: import org.apache.xerces.impl.xs.XSGrammarBucket;
0040: import org.apache.xerces.impl.xs.XSGroupDecl;
0041: import org.apache.xerces.impl.xs.XSMessageFormatter;
0042: import org.apache.xerces.impl.xs.XSModelGroupImpl;
0043: import org.apache.xerces.impl.xs.XSParticleDecl;
0044: import org.apache.xerces.impl.xs.opti.ElementImpl;
0045: import org.apache.xerces.impl.xs.opti.SchemaDOMParser;
0046: import org.apache.xerces.impl.xs.opti.SchemaParsingConfig;
0047: import org.apache.xerces.impl.xs.util.SimpleLocator;
0048:
0049: import org.apache.xerces.util.DOMUtil;
0050: import org.apache.xerces.parsers.SAXParser;
0051: import org.apache.xerces.parsers.XML11Configuration;
0052: import org.apache.xerces.util.DOMInputSource;
0053: import org.apache.xerces.util.DefaultErrorHandler;
0054: import org.apache.xerces.util.SAXInputSource;
0055: import org.apache.xerces.util.SymbolTable;
0056: import org.apache.xerces.util.XMLSymbols;
0057: import org.apache.xerces.util.URI.MalformedURIException;
0058: import org.apache.xerces.xni.QName;
0059: import org.apache.xerces.xni.grammars.Grammar;
0060: import org.apache.xerces.xni.grammars.XMLGrammarDescription;
0061: import org.apache.xerces.xni.grammars.XMLGrammarPool;
0062: import org.apache.xerces.xni.grammars.XMLSchemaDescription;
0063: import org.apache.xerces.xni.parser.XMLComponentManager;
0064: import org.apache.xerces.xni.parser.XMLConfigurationException;
0065: import org.apache.xerces.xni.parser.XMLEntityResolver;
0066: import org.apache.xerces.xni.parser.XMLErrorHandler;
0067: import org.apache.xerces.xni.parser.XMLInputSource;
0068: import org.apache.xerces.xs.XSObject;
0069: import org.apache.xerces.xs.XSParticle;
0070: import org.w3c.dom.Document;
0071: import org.w3c.dom.Element;
0072: import org.w3c.dom.Node;
0073: import org.xml.sax.InputSource;
0074: import org.xml.sax.SAXException;
0075: import org.xml.sax.XMLReader;
0076: import org.xml.sax.helpers.XMLReaderFactory;
0077:
0078: /**
0079: * The purpose of this class is to co-ordinate the construction of a
0080: * grammar object corresponding to a schema. To do this, it must be
0081: * prepared to parse several schema documents (for instance if the
0082: * schema document originally referred to contains <include> or
0083: * <redefined> information items). If any of the schemas imports a
0084: * schema, other grammars may be constructed as a side-effect.
0085: *
0086: * @xerces.internal
0087: *
0088: * @author Neil Graham, IBM
0089: * @author Pavani Mukthipudi, Sun Microsystems
0090: *
0091: * @version $Id: XSDHandler.java 449487 2006-09-24 21:11:28Z mrglavas $
0092: */
0093: public class XSDHandler {
0094:
0095: /** Feature identifier: validation. */
0096: protected static final String VALIDATION = Constants.SAX_FEATURE_PREFIX
0097: + Constants.VALIDATION_FEATURE;
0098:
0099: /** feature identifier: XML Schema validation */
0100: protected static final String XMLSCHEMA_VALIDATION = Constants.XERCES_FEATURE_PREFIX
0101: + Constants.SCHEMA_VALIDATION_FEATURE;
0102:
0103: /** Feature identifier: allow java encodings */
0104: protected static final String ALLOW_JAVA_ENCODINGS = Constants.XERCES_FEATURE_PREFIX
0105: + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
0106:
0107: /** Feature identifier: continue after fatal error */
0108: protected static final String CONTINUE_AFTER_FATAL_ERROR = Constants.XERCES_FEATURE_PREFIX
0109: + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
0110:
0111: /** Feature identifier: allow java encodings */
0112: protected static final String STANDARD_URI_CONFORMANT_FEATURE = Constants.XERCES_FEATURE_PREFIX
0113: + Constants.STANDARD_URI_CONFORMANT_FEATURE;
0114:
0115: /** Feature: disallow doctype*/
0116: protected static final String DISALLOW_DOCTYPE = Constants.XERCES_FEATURE_PREFIX
0117: + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
0118:
0119: /** Feature: generate synthetic annotations */
0120: protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = Constants.XERCES_FEATURE_PREFIX
0121: + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
0122:
0123: /** Feature identifier: validate annotations. */
0124: protected static final String VALIDATE_ANNOTATIONS = Constants.XERCES_FEATURE_PREFIX
0125: + Constants.VALIDATE_ANNOTATIONS_FEATURE;
0126:
0127: /** Feature identifier: honour all schemaLocations */
0128: protected static final String HONOUR_ALL_SCHEMALOCATIONS = Constants.XERCES_FEATURE_PREFIX
0129: + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
0130:
0131: /** Feature identifier: namespace prefixes. */
0132: private static final String NAMESPACE_PREFIXES = Constants.SAX_FEATURE_PREFIX
0133: + Constants.NAMESPACE_PREFIXES_FEATURE;
0134:
0135: /** Feature identifier: string interning. */
0136: protected static final String STRING_INTERNING = Constants.SAX_FEATURE_PREFIX
0137: + Constants.STRING_INTERNING_FEATURE;
0138:
0139: /** Property identifier: error handler. */
0140: protected static final String ERROR_HANDLER = Constants.XERCES_PROPERTY_PREFIX
0141: + Constants.ERROR_HANDLER_PROPERTY;
0142:
0143: /** Property identifier: JAXP schema source. */
0144: protected static final String JAXP_SCHEMA_SOURCE = Constants.JAXP_PROPERTY_PREFIX
0145: + Constants.SCHEMA_SOURCE;
0146:
0147: /** Property identifier: entity resolver. */
0148: public static final String ENTITY_RESOLVER = Constants.XERCES_PROPERTY_PREFIX
0149: + Constants.ENTITY_RESOLVER_PROPERTY;
0150: /** Property identifier: entity manager. */
0151: protected static final String ENTITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX
0152: + Constants.ENTITY_MANAGER_PROPERTY;
0153:
0154: /** Property identifier: error reporter. */
0155: public static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX
0156: + Constants.ERROR_REPORTER_PROPERTY;
0157:
0158: /** Property identifier: grammar pool. */
0159: public static final String XMLGRAMMAR_POOL = Constants.XERCES_PROPERTY_PREFIX
0160: + Constants.XMLGRAMMAR_POOL_PROPERTY;
0161:
0162: /** Property identifier: symbol table. */
0163: public static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX
0164: + Constants.SYMBOL_TABLE_PROPERTY;
0165:
0166: /** Property identifier: security manager. */
0167: protected static final String SECURITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX
0168: + Constants.SECURITY_MANAGER_PROPERTY;
0169:
0170: protected static final boolean DEBUG_NODE_POOL = false;
0171:
0172: // Data
0173:
0174: // different sorts of declarations; should make lookup and
0175: // traverser calling more efficient/less bulky.
0176: final static int ATTRIBUTE_TYPE = 1;
0177: final static int ATTRIBUTEGROUP_TYPE = 2;
0178: final static int ELEMENT_TYPE = 3;
0179: final static int GROUP_TYPE = 4;
0180: final static int IDENTITYCONSTRAINT_TYPE = 5;
0181: final static int NOTATION_TYPE = 6;
0182: final static int TYPEDECL_TYPE = 7;
0183:
0184: // this string gets appended to redefined names; it's purpose is to be
0185: // as unlikely as possible to cause collisions.
0186: public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
0187:
0188: //
0189: //protected data that can be accessable by any traverser
0190: // stores <notation> decl
0191: protected Hashtable fNotationRegistry = new Hashtable();
0192:
0193: protected XSDeclarationPool fDeclPool = null;
0194:
0195: // These tables correspond to the symbol spaces defined in the
0196: // spec.
0197: // They are keyed with a QName (that is, String("URI,localpart) and
0198: // their values are nodes corresponding to the given name's decl.
0199: // By asking the node for its ownerDocument and looking in
0200: // XSDocumentInfoRegistry we can easily get the corresponding
0201: // XSDocumentInfo object.
0202: private Hashtable fUnparsedAttributeRegistry = new Hashtable();
0203: private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable();
0204: private Hashtable fUnparsedElementRegistry = new Hashtable();
0205: private Hashtable fUnparsedGroupRegistry = new Hashtable();
0206: private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable();
0207: private Hashtable fUnparsedNotationRegistry = new Hashtable();
0208: private Hashtable fUnparsedTypeRegistry = new Hashtable();
0209: // Compensation for the above hashtables to locate XSDocumentInfo,
0210: // Since we may take Schema Element directly, so can not get the
0211: // corresponding XSDocumentInfo object just using above hashtables.
0212: private Hashtable fUnparsedAttributeRegistrySub = new Hashtable();
0213: private Hashtable fUnparsedAttributeGroupRegistrySub = new Hashtable();
0214: private Hashtable fUnparsedElementRegistrySub = new Hashtable();
0215: private Hashtable fUnparsedGroupRegistrySub = new Hashtable();
0216: private Hashtable fUnparsedIdentityConstraintRegistrySub = new Hashtable();
0217: private Hashtable fUnparsedNotationRegistrySub = new Hashtable();
0218: private Hashtable fUnparsedTypeRegistrySub = new Hashtable();
0219:
0220: // this is keyed with a documentNode (or the schemaRoot nodes
0221: // contained in the XSDocumentInfo objects) and its value is the
0222: // XSDocumentInfo object corresponding to that document.
0223: // Basically, the function of this registry is to be a link
0224: // between the nodes we fetch from calls to the fUnparsed*
0225: // arrays and the XSDocumentInfos they live in.
0226: private Hashtable fXSDocumentInfoRegistry = new Hashtable();
0227:
0228: // this hashtable is keyed on by XSDocumentInfo objects. Its values
0229: // are Vectors containing the XSDocumentInfo objects <include>d,
0230: // <import>ed or <redefine>d by the key XSDocumentInfo.
0231: private Hashtable fDependencyMap = new Hashtable();
0232:
0233: // this hashtable is keyed on by a target namespace. Its values
0234: // are Vectors containing namespaces imported by schema documents
0235: // with the key target namespace.
0236: // if an imprted schema has absent namespace, the value "null" is stored.
0237: private Hashtable fImportMap = new Hashtable();
0238: // all namespaces that imports other namespaces
0239: // if the importing schema has absent namespace, empty string is stored.
0240: // (because the key of a hashtable can't be null.)
0241: private Vector fAllTNSs = new Vector();
0242: // stores instance document mappings between namespaces and schema hints
0243: private Hashtable fLocationPairs = null;
0244: private static final Hashtable EMPTY_TABLE = new Hashtable();
0245:
0246: // Records which nodes are hidden when the input is a DOMInputSource.
0247: Hashtable fHiddenNodes = null;
0248:
0249: // convenience methods
0250: private String null2EmptyString(String ns) {
0251: return ns == null ? XMLSymbols.EMPTY_STRING : ns;
0252: }
0253:
0254: private String emptyString2Null(String ns) {
0255: return ns == XMLSymbols.EMPTY_STRING ? null : ns;
0256: }
0257:
0258: // use Schema Element to lookup the SystemId.
0259: private String doc2SystemId(Element ele) {
0260: String documentURI = null;
0261: /**
0262: * REVISIT: Casting until DOM Level 3 interfaces are available. -- mrglavas
0263: */
0264: if (ele.getOwnerDocument() instanceof org.apache.xerces.impl.xs.opti.SchemaDOM) {
0265: documentURI = ((org.apache.xerces.impl.xs.opti.SchemaDOM) ele
0266: .getOwnerDocument()).getDocumentURI();
0267: }
0268: return documentURI != null ? documentURI
0269: : (String) fDoc2SystemId.get(ele);
0270: }
0271:
0272: // This vector stores strings which are combinations of the
0273: // publicId and systemId of the inputSource corresponding to a
0274: // schema document. This combination is used so that the user's
0275: // EntityResolver can provide a consistent way of identifying a
0276: // schema document that is included in multiple other schemas.
0277: private Hashtable fTraversed = new Hashtable();
0278:
0279: // this hashtable contains a mapping from Schema Element to its systemId
0280: // this is useful to resolve a uri relative to the referring document
0281: private Hashtable fDoc2SystemId = new Hashtable();
0282:
0283: // the primary XSDocumentInfo we were called to parse
0284: private XSDocumentInfo fRoot = null;
0285:
0286: // This hashtable's job is to act as a link between the Schema Element and its
0287: // XSDocumentInfo object.
0288: private Hashtable fDoc2XSDocumentMap = new Hashtable();
0289:
0290: // map between <redefine> elements and the XSDocumentInfo
0291: // objects that correspond to the documents being redefined.
0292: private Hashtable fRedefine2XSDMap = new Hashtable();
0293:
0294: // map between <redefine> elements and the namespace support
0295: private Hashtable fRedefine2NSSupport = new Hashtable();
0296:
0297: // these objects store a mapping between the names of redefining
0298: // groups/attributeGroups and the groups/AttributeGroups which
0299: // they redefine by restriction (implicitly). It is up to the
0300: // Group and AttributeGroup traversers to check these restrictions for
0301: // validity.
0302: private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable();
0303: private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable();
0304:
0305: // a variable storing whether the last schema document
0306: // processed (by getSchema) was a duplicate.
0307: private boolean fLastSchemaWasDuplicate;
0308:
0309: // validate annotations feature
0310: private boolean fValidateAnnotations = false;
0311:
0312: //handle multiple import feature
0313: private boolean fHonourAllSchemaLocations = false;
0314:
0315: // the XMLErrorReporter
0316: private XMLErrorReporter fErrorReporter;
0317: private XMLEntityResolver fEntityResolver;
0318:
0319: // the XSAttributeChecker
0320: private XSAttributeChecker fAttributeChecker;
0321:
0322: // the symbol table
0323: private SymbolTable fSymbolTable;
0324:
0325: // the GrammarResolver
0326: private XSGrammarBucket fGrammarBucket;
0327:
0328: // the Grammar description
0329: private XSDDescription fSchemaGrammarDescription;
0330:
0331: // the Grammar Pool
0332: private XMLGrammarPool fGrammarPool;
0333:
0334: //************ Traversers **********
0335: XSDAttributeGroupTraverser fAttributeGroupTraverser;
0336: XSDAttributeTraverser fAttributeTraverser;
0337: XSDComplexTypeTraverser fComplexTypeTraverser;
0338: XSDElementTraverser fElementTraverser;
0339: XSDGroupTraverser fGroupTraverser;
0340: XSDKeyrefTraverser fKeyrefTraverser;
0341: XSDNotationTraverser fNotationTraverser;
0342: XSDSimpleTypeTraverser fSimpleTypeTraverser;
0343: XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser;
0344: XSDWildcardTraverser fWildCardTraverser;
0345:
0346: SchemaDOMParser fSchemaParser;
0347: SchemaContentHandler fXSContentHandler;
0348: XML11Configuration fAnnotationValidator;
0349: XSAnnotationGrammarPool fGrammarBucketAdapter;
0350:
0351: // these data members are needed for the deferred traversal
0352: // of local elements.
0353:
0354: // the initial size of the array to store deferred local elements
0355: private static final int INIT_STACK_SIZE = 30;
0356: // the incremental size of the array to store deferred local elements
0357: private static final int INC_STACK_SIZE = 10;
0358: // current position of the array (# of deferred local elements)
0359: private int fLocalElemStackPos = 0;
0360:
0361: private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE];
0362: private Element[] fLocalElementDecl = new Element[INIT_STACK_SIZE];
0363: private XSDocumentInfo[] fLocalElementDecl_schema = new XSDocumentInfo[INIT_STACK_SIZE]; //JACK
0364: private int[] fAllContext = new int[INIT_STACK_SIZE];
0365: private XSObject[] fParent = new XSObject[INIT_STACK_SIZE];
0366: private String[][] fLocalElemNamespaceContext = new String[INIT_STACK_SIZE][1];
0367:
0368: // these data members are needed for the deferred traversal
0369: // of keyrefs.
0370:
0371: // the initial size of the array to store deferred keyrefs
0372: private static final int INIT_KEYREF_STACK = 2;
0373: // the incremental size of the array to store deferred keyrefs
0374: private static final int INC_KEYREF_STACK_AMOUNT = 2;
0375: // current position of the array (# of deferred keyrefs)
0376: private int fKeyrefStackPos = 0;
0377:
0378: private Element[] fKeyrefs = new Element[INIT_KEYREF_STACK];
0379: private XSDocumentInfo[] fKeyrefsMapXSDocumentInfo = new XSDocumentInfo[INIT_KEYREF_STACK];
0380: private XSElementDecl[] fKeyrefElems = new XSElementDecl[INIT_KEYREF_STACK];
0381: private String[][] fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1];
0382:
0383: // Constructors
0384: public XSDHandler() {
0385: fHiddenNodes = new Hashtable();
0386: fSchemaParser = new SchemaDOMParser(new SchemaParsingConfig());
0387: }
0388:
0389: // it should be possible to use the same XSDHandler to parse
0390: // multiple schema documents; this will allow one to be
0391: // constructed.
0392: public XSDHandler(XSGrammarBucket gBucket) {
0393: this ();
0394: fGrammarBucket = gBucket;
0395:
0396: // Note: don't use SchemaConfiguration internally
0397: // we will get stack overflaw because
0398: // XMLSchemaValidator will be instantiating XSDHandler...
0399: fSchemaGrammarDescription = new XSDDescription();
0400: } // end constructor
0401:
0402: /**
0403: * This method initiates the parse of a schema. It will likely be
0404: * called from the Validator and it will make the
0405: * resulting grammar available; it returns a reference to this object just
0406: * in case. A reset(XMLComponentManager) must be called before this methods is called.
0407: * @param is
0408: * @param desc
0409: * @param locationPairs
0410: * @return the SchemaGrammar
0411: * @throws IOException
0412: */
0413: public SchemaGrammar parseSchema(XMLInputSource is,
0414: XSDDescription desc, Hashtable locationPairs)
0415: throws IOException {
0416: fLocationPairs = locationPairs;
0417: fSchemaParser.resetNodePool();
0418: SchemaGrammar grammar = null;
0419: String schemaNamespace = null;
0420: short referType = desc.getContextType();
0421: // if loading using JAXP schemaSource property, or using grammar caching loadGrammar
0422: // the desc.targetNamespace is always null.
0423: // Therefore we should not attempt to find out if
0424: // the schema is already in the bucket, since in the case we have
0425: // no namespace schema in the bucket, findGrammar will always return the
0426: // no namespace schema.
0427: if (referType != XSDDescription.CONTEXT_PREPARSE) {
0428: // first try to find it in the bucket/pool, return if one is found
0429: if (fHonourAllSchemaLocations
0430: && referType == XSDDescription.CONTEXT_IMPORT
0431: && isExistingGrammar(desc)) {
0432: grammar = fGrammarBucket.getGrammar(desc
0433: .getTargetNamespace());
0434: } else {
0435: grammar = findGrammar(desc);
0436: }
0437: if (grammar != null)
0438: return grammar;
0439: schemaNamespace = desc.getTargetNamespace();
0440: // handle empty string URI as null
0441: if (schemaNamespace != null) {
0442: schemaNamespace = fSymbolTable
0443: .addSymbol(schemaNamespace);
0444: }
0445: }
0446:
0447: // before parsing a schema, need to clear registries associated with
0448: // parsing schemas
0449: prepareForParse();
0450:
0451: Document schemaRootDoc = null;
0452: Element schemaRoot = null;
0453: // first phase: construct trees.
0454: if (is instanceof DOMInputSource) {
0455: //clean up the field fHiddenNodes, used for DOMInputSource
0456: fHiddenNodes.clear();
0457: Node domNode = ((DOMInputSource) is).getNode();
0458:
0459: if (domNode instanceof Document) {
0460: schemaRootDoc = (Document) domNode;
0461: schemaRoot = DOMUtil.getRoot(schemaRootDoc);
0462: } else if (domNode instanceof Element) {
0463: schemaRoot = (Element) domNode;
0464: } else {
0465: return null;
0466: }
0467: } // DOMInputSource
0468: else if (is instanceof SAXInputSource) {
0469: XMLReader parser = ((SAXInputSource) is).getXMLReader();
0470: InputSource inputSource = ((SAXInputSource) is)
0471: .getInputSource();
0472: boolean namespacePrefixes = false;
0473: if (parser != null) {
0474: try {
0475: namespacePrefixes = parser
0476: .getFeature(NAMESPACE_PREFIXES);
0477: } catch (SAXException se) {
0478: }
0479: } else {
0480: try {
0481: parser = XMLReaderFactory.createXMLReader();
0482: }
0483: // If something went wrong with the factory
0484: // just use our own SAX parser.
0485: catch (SAXException se) {
0486: parser = new SAXParser();
0487: }
0488: try {
0489: parser.setFeature(NAMESPACE_PREFIXES, true);
0490: namespacePrefixes = true;
0491: } catch (SAXException se) {
0492: }
0493: }
0494: // If XML names and Namespace URIs are already internalized we
0495: // can avoid running them through the SymbolTable.
0496: boolean stringsInternalized = false;
0497: try {
0498: stringsInternalized = parser
0499: .getFeature(STRING_INTERNING);
0500: } catch (SAXException exc) {
0501: // The feature isn't recognized or getting it is not supported.
0502: // In either case, assume that strings are not internalized.
0503: }
0504: if (fXSContentHandler == null) {
0505: fXSContentHandler = new SchemaContentHandler();
0506: }
0507: fXSContentHandler.reset(fSchemaParser, fSymbolTable,
0508: namespacePrefixes, stringsInternalized);
0509: parser.setContentHandler(fXSContentHandler);
0510: parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
0511: try {
0512: parser.parse(inputSource);
0513: } catch (SAXException se) {
0514: return null;
0515: }
0516: schemaRootDoc = fXSContentHandler.getDocument();
0517: if (schemaRootDoc == null) {
0518: // something went wrong right off the hop
0519: return null;
0520: }
0521: schemaRoot = DOMUtil.getRoot(schemaRootDoc);
0522: } else {
0523: schemaRoot = getSchemaDocument(schemaNamespace, is,
0524: referType == XSDDescription.CONTEXT_PREPARSE,
0525: referType, null);
0526:
0527: }//is instanceof XMLInputSource
0528:
0529: if (schemaRoot == null) {
0530: // something went wrong right off the hop
0531: return null;
0532: }
0533:
0534: if (referType == XSDDescription.CONTEXT_PREPARSE) {
0535: Element schemaElem = schemaRoot;
0536: schemaNamespace = DOMUtil.getAttrValue(schemaElem,
0537: SchemaSymbols.ATT_TARGETNAMESPACE);
0538: if (schemaNamespace != null && schemaNamespace.length() > 0) {
0539: // Since now we've discovered a namespace, we need to update xsd key
0540: // and store this schema in traversed schemas bucket
0541: schemaNamespace = fSymbolTable
0542: .addSymbol(schemaNamespace);
0543: desc.setTargetNamespace(schemaNamespace);
0544: } else {
0545: schemaNamespace = null;
0546: }
0547: grammar = findGrammar(desc);
0548: if (grammar != null)
0549: return grammar;
0550: String schemaId = XMLEntityManager.expandSystemId(is
0551: .getSystemId(), is.getBaseSystemId(), false);
0552: XSDKey key = new XSDKey(schemaId, referType,
0553: schemaNamespace);
0554: fTraversed.put(key, schemaRoot);
0555: if (schemaId != null) {
0556: fDoc2SystemId.put(schemaRoot, schemaId);
0557: }
0558: }
0559:
0560: // before constructing trees and traversing a schema, need to reset
0561: // all traversers and clear all registries
0562: prepareForTraverse();
0563:
0564: fRoot = constructTrees(schemaRoot, is.getSystemId(), desc);
0565: if (fRoot == null) {
0566: return null;
0567: }
0568:
0569: // second phase: fill global registries.
0570: buildGlobalNameRegistries();
0571:
0572: // third phase: call traversers
0573: ArrayList annotationInfo = fValidateAnnotations ? new ArrayList()
0574: : null;
0575: traverseSchemas(annotationInfo);
0576:
0577: // fourth phase: handle local element decls
0578: traverseLocalElements();
0579:
0580: // fifth phase: handle Keyrefs
0581: resolveKeyRefs();
0582:
0583: // sixth phase: validate attribute of non-schema namespaces
0584: // REVISIT: skip this for now. we really don't want to do it.
0585: //fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket);
0586:
0587: // seventh phase: store imported grammars
0588: // for all grammars with <import>s
0589: for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
0590: // get its target namespace
0591: String tns = (String) fAllTNSs.elementAt(i);
0592: // get all namespaces it imports
0593: Vector ins = (Vector) fImportMap.get(tns);
0594: // get the grammar
0595: SchemaGrammar sg = fGrammarBucket
0596: .getGrammar(emptyString2Null(tns));
0597: if (sg == null)
0598: continue;
0599: SchemaGrammar isg;
0600: // for imported namespace
0601: int count = 0;
0602: for (int j = 0; j < ins.size(); j++) {
0603: // get imported grammar
0604: isg = fGrammarBucket.getGrammar((String) ins
0605: .elementAt(j));
0606: // reuse the same vector
0607: if (isg != null)
0608: ins.setElementAt(isg, count++);
0609: }
0610: ins.setSize(count);
0611: // set the imported grammars
0612: sg.setImportedGrammars(ins);
0613: }
0614:
0615: /** validate annotations **/
0616: if (fValidateAnnotations && annotationInfo.size() > 0) {
0617: validateAnnotations(annotationInfo);
0618: }
0619:
0620: // and return.
0621: return fGrammarBucket.getGrammar(fRoot.fTargetNamespace);
0622: } // end parseSchema
0623:
0624: private void validateAnnotations(ArrayList annotationInfo) {
0625: if (fAnnotationValidator == null) {
0626: createAnnotationValidator();
0627: }
0628: final int size = annotationInfo.size();
0629: final XMLInputSource src = new XMLInputSource(null, null, null);
0630: fGrammarBucketAdapter.refreshGrammars(fGrammarBucket);
0631: for (int i = 0; i < size; i += 2) {
0632: src.setSystemId((String) annotationInfo.get(i));
0633: XSAnnotationInfo annotation = (XSAnnotationInfo) annotationInfo
0634: .get(i + 1);
0635: while (annotation != null) {
0636: src.setCharacterStream(new StringReader(
0637: annotation.fAnnotation));
0638: try {
0639: fAnnotationValidator.parse(src);
0640: } catch (IOException exc) {
0641: }
0642: annotation = annotation.next;
0643: }
0644: }
0645: }
0646:
0647: private void createAnnotationValidator() {
0648: fAnnotationValidator = new XML11Configuration();
0649: fGrammarBucketAdapter = new XSAnnotationGrammarPool();
0650: fAnnotationValidator.setFeature(VALIDATION, true);
0651: fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true);
0652: fAnnotationValidator.setProperty(XMLGRAMMAR_POOL,
0653: fGrammarBucketAdapter);
0654: /** Set error handler. **/
0655: XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler();
0656: fAnnotationValidator.setProperty(ERROR_HANDLER,
0657: (errorHandler != null) ? errorHandler
0658: : new DefaultErrorHandler());
0659: }
0660:
0661: /**
0662: * Pull the grammar out of the bucket simply using
0663: * its TNS as a key
0664: */
0665: SchemaGrammar getGrammar(String tns) {
0666: return fGrammarBucket.getGrammar(tns);
0667: }
0668:
0669: /**
0670: * First try to find a grammar in the bucket, if failed, consult the
0671: * grammar pool. If a grammar is found in the pool, then add it (and all
0672: * imported ones) into the bucket.
0673: */
0674: protected SchemaGrammar findGrammar(XSDDescription desc) {
0675: SchemaGrammar sg = fGrammarBucket.getGrammar(desc
0676: .getTargetNamespace());
0677: if (sg == null) {
0678: if (fGrammarPool != null) {
0679: sg = (SchemaGrammar) fGrammarPool.retrieveGrammar(desc);
0680: if (sg != null) {
0681: // put this grammar into the bucket, along with grammars
0682: // imported by it (directly or indirectly)
0683: if (!fGrammarBucket.putGrammar(sg, true)) {
0684: // REVISIT: a conflict between new grammar(s) and grammars
0685: // in the bucket. What to do? A warning? An exception?
0686: reportSchemaWarning("GrammarConflict", null,
0687: null);
0688: sg = null;
0689: }
0690: }
0691: }
0692: }
0693: return sg;
0694: }
0695:
0696: // may wish to have setter methods for ErrorHandler,
0697: // EntityResolver...
0698:
0699: private static final String[][] NS_ERROR_CODES = {
0700: { "src-include.2.1", "src-include.2.1" },
0701: { "src-redefine.3.1", "src-redefine.3.1" },
0702: { "src-import.3.1", "src-import.3.2" }, null,
0703: { "TargetNamespace.1", "TargetNamespace.2" },
0704: { "TargetNamespace.1", "TargetNamespace.2" },
0705: { "TargetNamespace.1", "TargetNamespace.2" },
0706: { "TargetNamespace.1", "TargetNamespace.2" } };
0707:
0708: private static final String[] ELE_ERROR_CODES = { "src-include.1",
0709: "src-redefine.2", "src-import.2", "schema_reference.4",
0710: "schema_reference.4", "schema_reference.4",
0711: "schema_reference.4", "schema_reference.4" };
0712:
0713: // This method does several things:
0714: // It constructs an instance of an XSDocumentInfo object using the
0715: // schemaRoot node. Then, for each <include>,
0716: // <redefine>, and <import> children, it attempts to resolve the
0717: // requested schema document, initiates a DOM parse, and calls
0718: // itself recursively on that document's root. It also records in
0719: // the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo
0720: // depends on.
0721: // It also makes sure the targetNamespace of the schema it was
0722: // called to parse is correct.
0723: protected XSDocumentInfo constructTrees(Element schemaRoot,
0724: String locationHint, XSDDescription desc) {
0725: if (schemaRoot == null)
0726: return null;
0727: String callerTNS = desc.getTargetNamespace();
0728: short referType = desc.getContextType();
0729:
0730: XSDocumentInfo currSchemaInfo = null;
0731: try {
0732: // note that attributes are freed at end of traverseSchemas()
0733: currSchemaInfo = new XSDocumentInfo(schemaRoot,
0734: fAttributeChecker, fSymbolTable);
0735: } catch (XMLSchemaException se) {
0736: reportSchemaError(ELE_ERROR_CODES[referType],
0737: new Object[] { locationHint }, schemaRoot);
0738: return null;
0739: }
0740: // targetNamespace="" is not valid, issue a warning, and ignore it
0741: if (currSchemaInfo.fTargetNamespace != null
0742: && currSchemaInfo.fTargetNamespace.length() == 0) {
0743: reportSchemaWarning("EmptyTargetNamespace",
0744: new Object[] { locationHint }, schemaRoot);
0745: currSchemaInfo.fTargetNamespace = null;
0746: }
0747:
0748: if (callerTNS != null) {
0749: // the second index to the NS_ERROR_CODES array
0750: // if the caller/expected NS is not absent, we use the first column
0751: int secondIdx = 0;
0752: // for include and redefine
0753: if (referType == XSDDescription.CONTEXT_INCLUDE
0754: || referType == XSDDescription.CONTEXT_REDEFINE) {
0755: // if the referred document has no targetNamespace,
0756: // it's a chameleon schema
0757: if (currSchemaInfo.fTargetNamespace == null) {
0758: currSchemaInfo.fTargetNamespace = callerTNS;
0759: currSchemaInfo.fIsChameleonSchema = true;
0760: }
0761: // if the referred document has a target namespace differing
0762: // from the caller, it's an error
0763: else if (callerTNS != currSchemaInfo.fTargetNamespace) {
0764: reportSchemaError(
0765: NS_ERROR_CODES[referType][secondIdx],
0766: new Object[] { callerTNS,
0767: currSchemaInfo.fTargetNamespace },
0768: schemaRoot);
0769: return null;
0770: }
0771: }
0772: // for instance and import, the two NS's must be the same
0773: else if (referType != XSDDescription.CONTEXT_PREPARSE
0774: && callerTNS != currSchemaInfo.fTargetNamespace) {
0775: reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
0776: new Object[] { callerTNS,
0777: currSchemaInfo.fTargetNamespace },
0778: schemaRoot);
0779: return null;
0780: }
0781: }
0782: // now there is no caller/expected NS, it's an error for the referred
0783: // document to have a target namespace, unless we are preparsing a schema
0784: else if (currSchemaInfo.fTargetNamespace != null) {
0785: // set the target namespace of the description
0786: if (referType == XSDDescription.CONTEXT_PREPARSE) {
0787: desc
0788: .setTargetNamespace(currSchemaInfo.fTargetNamespace);
0789: callerTNS = currSchemaInfo.fTargetNamespace;
0790: } else {
0791: // the second index to the NS_ERROR_CODES array
0792: // if the caller/expected NS is absent, we use the second column
0793: int secondIdx = 1;
0794: reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
0795: new Object[] { callerTNS,
0796: currSchemaInfo.fTargetNamespace },
0797: schemaRoot);
0798: return null;
0799: }
0800: }
0801: // the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null)
0802: // are valid
0803:
0804: // a schema document can always access it's own target namespace
0805: currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace);
0806:
0807: SchemaGrammar sg = null;
0808:
0809: if (referType == XSDDescription.CONTEXT_INCLUDE
0810: || referType == XSDDescription.CONTEXT_REDEFINE) {
0811: sg = fGrammarBucket
0812: .getGrammar(currSchemaInfo.fTargetNamespace);
0813: } else if (fHonourAllSchemaLocations
0814: && referType == XSDDescription.CONTEXT_IMPORT) {
0815: sg = findGrammar(desc);
0816: if (sg == null) {
0817: sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace,
0818: desc.makeClone(), fSymbolTable);
0819: fGrammarBucket.putGrammar(sg);
0820: }
0821: } else {
0822: sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace,
0823: desc.makeClone(), fSymbolTable);
0824: fGrammarBucket.putGrammar(sg);
0825: }
0826:
0827: // store the document and its location
0828: // REVISIT: don't expose the DOM tree
0829: sg.addDocument(null, (String) fDoc2SystemId
0830: .get(currSchemaInfo.fSchemaElement));
0831:
0832: fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
0833: Vector dependencies = new Vector();
0834: Element rootNode = schemaRoot;
0835:
0836: Element newSchemaRoot = null;
0837: for (Element child = DOMUtil.getFirstChildElement(rootNode); child != null; child = DOMUtil
0838: .getNextSiblingElement(child)) {
0839: String schemaNamespace = null;
0840: String schemaHint = null;
0841: String localName = DOMUtil.getLocalName(child);
0842:
0843: short refType = -1;
0844:
0845: if (localName.equals(SchemaSymbols.ELT_ANNOTATION))
0846: continue;
0847: else if (localName.equals(SchemaSymbols.ELT_IMPORT)) {
0848: refType = XSDDescription.CONTEXT_IMPORT;
0849: // have to handle some validation here too!
0850: // call XSAttributeChecker to fill in attrs
0851: Object[] importAttrs = fAttributeChecker
0852: .checkAttributes(child, true, currSchemaInfo);
0853: schemaHint = (String) importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
0854: schemaNamespace = (String) importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE];
0855: if (schemaNamespace != null)
0856: schemaNamespace = fSymbolTable
0857: .addSymbol(schemaNamespace);
0858: // a document can't import another document with the same namespace
0859: if (schemaNamespace == currSchemaInfo.fTargetNamespace) {
0860: reportSchemaError(
0861: schemaNamespace != null ? "src-import.1.1"
0862: : "src-import.1.2",
0863: new Object[] { schemaNamespace }, child);
0864: }
0865:
0866: // check contents and process optional annotations
0867: Element importChild = DOMUtil
0868: .getFirstChildElement(child);
0869: if (importChild != null) {
0870: String importComponentType = DOMUtil
0871: .getLocalName(importChild);
0872: if (importComponentType
0873: .equals(SchemaSymbols.ELT_ANNOTATION)) {
0874: // promoting annotations to parent component
0875: sg.addAnnotation(fElementTraverser
0876: .traverseAnnotationDecl(importChild,
0877: importAttrs, true,
0878: currSchemaInfo));
0879: } else {
0880: reportSchemaError("s4s-elt-must-match.1",
0881: new Object[] { localName,
0882: "annotation?",
0883: importComponentType }, child);
0884: }
0885: if (DOMUtil.getNextSiblingElement(importChild) != null) {
0886: reportSchemaError(
0887: "s4s-elt-must-match.1",
0888: new Object[] {
0889: localName,
0890: "annotation?",
0891: DOMUtil
0892: .getLocalName(DOMUtil
0893: .getNextSiblingElement(importChild)) },
0894: child);
0895: }
0896: } else {
0897: String text = DOMUtil.getSyntheticAnnotation(child);
0898: if (text != null) {
0899: sg.addAnnotation(fElementTraverser
0900: .traverseSyntheticAnnotation(child,
0901: text, importAttrs, true,
0902: currSchemaInfo));
0903: }
0904: }
0905: fAttributeChecker.returnAttrArray(importAttrs,
0906: currSchemaInfo);
0907:
0908: // if this namespace has not been imported by this document,
0909: // then import if multiple imports support is enabled.
0910: if (currSchemaInfo.isAllowedNS(schemaNamespace)) {
0911: if (!fHonourAllSchemaLocations)
0912: continue;
0913: } else {
0914: currSchemaInfo.addAllowedNS(schemaNamespace);
0915: }
0916: // also record the fact that one namespace imports another one
0917: // convert null to ""
0918: String tns = null2EmptyString(currSchemaInfo.fTargetNamespace);
0919: // get all namespaces imported by this one
0920: Vector ins = (Vector) fImportMap.get(tns);
0921: // if no namespace was imported, create new Vector
0922: if (ins == null) {
0923: // record that this one imports other(s)
0924: fAllTNSs.addElement(tns);
0925: ins = new Vector();
0926: fImportMap.put(tns, ins);
0927: ins.addElement(schemaNamespace);
0928: } else if (!ins.contains(schemaNamespace)) {
0929: ins.addElement(schemaNamespace);
0930: }
0931:
0932: fSchemaGrammarDescription.reset();
0933: fSchemaGrammarDescription
0934: .setContextType(XSDDescription.CONTEXT_IMPORT);
0935: fSchemaGrammarDescription
0936: .setBaseSystemId(doc2SystemId(schemaRoot));
0937: fSchemaGrammarDescription
0938: .setLocationHints(new String[] { schemaHint });
0939: fSchemaGrammarDescription
0940: .setTargetNamespace(schemaNamespace);
0941:
0942: // if a grammar with the same namespace and location exists (or being
0943: // built), ignore this one (don't traverse it).
0944: if ((!fHonourAllSchemaLocations && findGrammar(fSchemaGrammarDescription) != null)
0945: || isExistingGrammar(fSchemaGrammarDescription))
0946: continue;
0947: // If "findGrammar" returns a grammar, then this is not the
0948: // the first time we see a location for a given namespace.
0949: // Don't consult the location pair hashtable in this case,
0950: // otherwise the location will be ignored because it'll get
0951: // resolved to the same location as the first hint.
0952: newSchemaRoot = resolveSchema(
0953: fSchemaGrammarDescription, false, child,
0954: findGrammar(fSchemaGrammarDescription) == null);
0955: } else if ((localName.equals(SchemaSymbols.ELT_INCLUDE))
0956: || (localName.equals(SchemaSymbols.ELT_REDEFINE))) {
0957: // validation for redefine/include will be the same here; just
0958: // make sure TNS is right (don't care about redef contents
0959: // yet).
0960: Object[] includeAttrs = fAttributeChecker
0961: .checkAttributes(child, true, currSchemaInfo);
0962: schemaHint = (String) includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
0963: // store the namespace decls of the redefine element
0964: if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
0965: fRedefine2NSSupport.put(child,
0966: new SchemaNamespaceSupport(
0967: currSchemaInfo.fNamespaceSupport));
0968: }
0969:
0970: // check annotations. Must do this here to avoid having to
0971: // re-parse attributes later
0972: if (localName.equals(SchemaSymbols.ELT_INCLUDE)) {
0973: Element includeChild = DOMUtil
0974: .getFirstChildElement(child);
0975: if (includeChild != null) {
0976: String includeComponentType = DOMUtil
0977: .getLocalName(includeChild);
0978: if (includeComponentType
0979: .equals(SchemaSymbols.ELT_ANNOTATION)) {
0980: // promoting annotations to parent component
0981: sg.addAnnotation(fElementTraverser
0982: .traverseAnnotationDecl(
0983: includeChild, includeAttrs,
0984: true, currSchemaInfo));
0985: } else {
0986: reportSchemaError("s4s-elt-must-match.1",
0987: new Object[] { localName,
0988: "annotation?",
0989: includeComponentType },
0990: child);
0991: }
0992: if (DOMUtil.getNextSiblingElement(includeChild) != null) {
0993: reportSchemaError(
0994: "s4s-elt-must-match.1",
0995: new Object[] {
0996: localName,
0997: "annotation?",
0998: DOMUtil
0999: .getLocalName(DOMUtil
1000: .getNextSiblingElement(includeChild)) },
1001: child);
1002: }
1003: } else {
1004: String text = DOMUtil
1005: .getSyntheticAnnotation(child);
1006: if (text != null) {
1007: sg.addAnnotation(fElementTraverser
1008: .traverseSyntheticAnnotation(child,
1009: text, includeAttrs, true,
1010: currSchemaInfo));
1011: }
1012: }
1013: } else {
1014: for (Element redefinedChild = DOMUtil
1015: .getFirstChildElement(child); redefinedChild != null; redefinedChild = DOMUtil
1016: .getNextSiblingElement(redefinedChild)) {
1017: String redefinedComponentType = DOMUtil
1018: .getLocalName(redefinedChild);
1019: if (redefinedComponentType
1020: .equals(SchemaSymbols.ELT_ANNOTATION)) {
1021: // promoting annotations to parent component
1022: sg.addAnnotation(fElementTraverser
1023: .traverseAnnotationDecl(
1024: redefinedChild,
1025: includeAttrs, true,
1026: currSchemaInfo));
1027: DOMUtil.setHidden(redefinedChild,
1028: fHiddenNodes);
1029: } else {
1030: String text = DOMUtil
1031: .getSyntheticAnnotation(child);
1032: if (text != null) {
1033: sg.addAnnotation(fElementTraverser
1034: .traverseSyntheticAnnotation(
1035: child, text,
1036: includeAttrs, true,
1037: currSchemaInfo));
1038: }
1039: }
1040: // catch all other content errors later
1041: }
1042: }
1043: fAttributeChecker.returnAttrArray(includeAttrs,
1044: currSchemaInfo);
1045: // schemaLocation is required on <include> and <redefine>
1046: if (schemaHint == null) {
1047: reportSchemaError("s4s-att-must-appear",
1048: new Object[] { "<include> or <redefine>",
1049: "schemaLocation" }, child);
1050: }
1051: // pass the systemId of the current document as the base systemId
1052: boolean mustResolve = false;
1053: refType = XSDDescription.CONTEXT_INCLUDE;
1054: if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
1055: mustResolve = nonAnnotationContent(child);
1056: refType = XSDDescription.CONTEXT_REDEFINE;
1057: }
1058: fSchemaGrammarDescription.reset();
1059: fSchemaGrammarDescription.setContextType(refType);
1060: fSchemaGrammarDescription
1061: .setBaseSystemId(doc2SystemId(schemaRoot));
1062: fSchemaGrammarDescription
1063: .setLocationHints(new String[] { schemaHint });
1064: fSchemaGrammarDescription.setTargetNamespace(callerTNS);
1065: newSchemaRoot = resolveSchema(
1066: fSchemaGrammarDescription, mustResolve, child,
1067: true);
1068: schemaNamespace = currSchemaInfo.fTargetNamespace;
1069: } else {
1070: // no more possibility of schema references in well-formed
1071: // schema...
1072: break;
1073: }
1074:
1075: // If the schema is duplicate, we needn't call constructTrees() again.
1076: // To handle mutual <include>s
1077: XSDocumentInfo newSchemaInfo = null;
1078: if (fLastSchemaWasDuplicate) {
1079: newSchemaInfo = newSchemaRoot == null ? null
1080: : (XSDocumentInfo) fDoc2XSDocumentMap
1081: .get(newSchemaRoot);
1082: } else {
1083: newSchemaInfo = constructTrees(newSchemaRoot,
1084: schemaHint, fSchemaGrammarDescription);
1085: }
1086:
1087: if (localName.equals(SchemaSymbols.ELT_REDEFINE)
1088: && newSchemaInfo != null) {
1089: // must record which schema we're redefining so that we can
1090: // rename the right things later!
1091: fRedefine2XSDMap.put(child, newSchemaInfo);
1092: }
1093: if (newSchemaRoot != null) {
1094: if (newSchemaInfo != null)
1095: dependencies.addElement(newSchemaInfo);
1096: newSchemaRoot = null;
1097: }
1098: }
1099:
1100: fDependencyMap.put(currSchemaInfo, dependencies);
1101: return currSchemaInfo;
1102: } // end constructTrees
1103:
1104: private boolean isExistingGrammar(XSDDescription desc) {
1105: SchemaGrammar sg = fGrammarBucket.getGrammar(desc
1106: .getTargetNamespace());
1107: if (sg == null) {
1108: return findGrammar(desc) != null;
1109: } else {
1110: try {
1111: return sg.getDocumentLocations().contains(
1112: XMLEntityManager.expandSystemId(desc
1113: .getLiteralSystemId(), desc
1114: .getBaseSystemId(), false));
1115: } catch (MalformedURIException e) {
1116: return false;
1117: }
1118: }
1119: }
1120:
1121: // This method builds registries for all globally-referenceable
1122: // names. A registry will be built for each symbol space defined
1123: // by the spec. It is also this method's job to rename redefined
1124: // components, and to record which components redefine others (so
1125: // that implicit redefinitions of groups and attributeGroups can be handled).
1126: protected void buildGlobalNameRegistries() {
1127:
1128: // Starting with fRoot, we examine each child of the schema
1129: // element. Skipping all imports and includes, we record the names
1130: // of all other global components (and children of <redefine>). We
1131: // also put <redefine> names in a registry that we look through in
1132: // case something needs renaming. Once we're done with a schema we
1133: // set its Document node to hidden so that we don't try to traverse
1134: // it again; then we look to its Dependency map entry. We keep a
1135: // stack of schemas that we haven't yet finished processing; this
1136: // is a depth-first traversal.
1137:
1138: Stack schemasToProcess = new Stack();
1139: schemasToProcess.push(fRoot);
1140:
1141: while (!schemasToProcess.empty()) {
1142: XSDocumentInfo currSchemaDoc = (XSDocumentInfo) schemasToProcess
1143: .pop();
1144: Element currDoc = currSchemaDoc.fSchemaElement;
1145: if (DOMUtil.isHidden(currDoc, fHiddenNodes)) {
1146: // must have processed this already!
1147: continue;
1148: }
1149:
1150: Element currRoot = currDoc;
1151: // process this schema's global decls
1152: boolean dependenciesCanOccur = true;
1153: for (Element globalComp = DOMUtil
1154: .getFirstChildElement(currRoot); globalComp != null; globalComp = DOMUtil
1155: .getNextSiblingElement(globalComp)) {
1156: // this loop makes sure the <schema> element ordering is
1157: // also valid.
1158: if (DOMUtil.getLocalName(globalComp).equals(
1159: SchemaSymbols.ELT_ANNOTATION)) {
1160: //skip it; traverse it later
1161: continue;
1162: } else if (DOMUtil.getLocalName(globalComp).equals(
1163: SchemaSymbols.ELT_INCLUDE)
1164: || DOMUtil.getLocalName(globalComp).equals(
1165: SchemaSymbols.ELT_IMPORT)) {
1166: if (!dependenciesCanOccur) {
1167: reportSchemaError("s4s-elt-invalid-content.3",
1168: new Object[] { DOMUtil
1169: .getLocalName(globalComp) },
1170: globalComp);
1171: }
1172: DOMUtil.setHidden(globalComp, fHiddenNodes);
1173: } else if (DOMUtil.getLocalName(globalComp).equals(
1174: SchemaSymbols.ELT_REDEFINE)) {
1175: if (!dependenciesCanOccur) {
1176: reportSchemaError("s4s-elt-invalid-content.3",
1177: new Object[] { DOMUtil
1178: .getLocalName(globalComp) },
1179: globalComp);
1180: }
1181: for (Element redefineComp = DOMUtil
1182: .getFirstChildElement(globalComp); redefineComp != null; redefineComp = DOMUtil
1183: .getNextSiblingElement(redefineComp)) {
1184: String lName = DOMUtil.getAttrValue(
1185: redefineComp, SchemaSymbols.ATT_NAME);
1186: if (lName.length() == 0) // an error we'll catch later
1187: continue;
1188: String qName = currSchemaDoc.fTargetNamespace == null ? ","
1189: + lName
1190: : currSchemaDoc.fTargetNamespace + ","
1191: + lName;
1192: String componentType = DOMUtil
1193: .getLocalName(redefineComp);
1194: if (componentType
1195: .equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1196: checkForDuplicateNames(qName,
1197: fUnparsedAttributeGroupRegistry,
1198: fUnparsedAttributeGroupRegistrySub,
1199: redefineComp, currSchemaDoc);
1200: // the check will have changed our name;
1201: String targetLName = DOMUtil.getAttrValue(
1202: redefineComp,
1203: SchemaSymbols.ATT_NAME)
1204: + REDEF_IDENTIFIER;
1205: // and all we need to do is error-check+rename our kkids:
1206: renameRedefiningComponents(currSchemaDoc,
1207: redefineComp,
1208: SchemaSymbols.ELT_ATTRIBUTEGROUP,
1209: lName, targetLName);
1210: } else if ((componentType
1211: .equals(SchemaSymbols.ELT_COMPLEXTYPE))
1212: || (componentType
1213: .equals(SchemaSymbols.ELT_SIMPLETYPE))) {
1214: checkForDuplicateNames(qName,
1215: fUnparsedTypeRegistry,
1216: fUnparsedTypeRegistrySub,
1217: redefineComp, currSchemaDoc);
1218: // the check will have changed our name;
1219: String targetLName = DOMUtil.getAttrValue(
1220: redefineComp,
1221: SchemaSymbols.ATT_NAME)
1222: + REDEF_IDENTIFIER;
1223: // and all we need to do is error-check+rename our kkids:
1224: if (componentType
1225: .equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1226: renameRedefiningComponents(
1227: currSchemaDoc, redefineComp,
1228: SchemaSymbols.ELT_COMPLEXTYPE,
1229: lName, targetLName);
1230: } else { // must be simpleType
1231: renameRedefiningComponents(
1232: currSchemaDoc, redefineComp,
1233: SchemaSymbols.ELT_SIMPLETYPE,
1234: lName, targetLName);
1235: }
1236: } else if (componentType
1237: .equals(SchemaSymbols.ELT_GROUP)) {
1238: checkForDuplicateNames(qName,
1239: fUnparsedGroupRegistry,
1240: fUnparsedGroupRegistrySub,
1241: redefineComp, currSchemaDoc);
1242: // the check will have changed our name;
1243: String targetLName = DOMUtil.getAttrValue(
1244: redefineComp,
1245: SchemaSymbols.ATT_NAME)
1246: + REDEF_IDENTIFIER;
1247: // and all we need to do is error-check+rename our kids:
1248: renameRedefiningComponents(currSchemaDoc,
1249: redefineComp,
1250: SchemaSymbols.ELT_GROUP, lName,
1251: targetLName);
1252: }
1253: } // end march through <redefine> children
1254: // and now set as traversed
1255: //DOMUtil.setHidden(globalComp);
1256: } else {
1257: dependenciesCanOccur = false;
1258: String lName = DOMUtil.getAttrValue(globalComp,
1259: SchemaSymbols.ATT_NAME);
1260: if (lName.length() == 0) // an error we'll catch later
1261: continue;
1262: String qName = currSchemaDoc.fTargetNamespace == null ? ","
1263: + lName
1264: : currSchemaDoc.fTargetNamespace + ","
1265: + lName;
1266: String componentType = DOMUtil
1267: .getLocalName(globalComp);
1268: if (componentType
1269: .equals(SchemaSymbols.ELT_ATTRIBUTE)) {
1270: checkForDuplicateNames(qName,
1271: fUnparsedAttributeRegistry,
1272: fUnparsedAttributeRegistrySub,
1273: globalComp, currSchemaDoc);
1274: } else if (componentType
1275: .equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1276: checkForDuplicateNames(qName,
1277: fUnparsedAttributeGroupRegistry,
1278: fUnparsedAttributeGroupRegistrySub,
1279: globalComp, currSchemaDoc);
1280: } else if ((componentType
1281: .equals(SchemaSymbols.ELT_COMPLEXTYPE))
1282: || (componentType
1283: .equals(SchemaSymbols.ELT_SIMPLETYPE))) {
1284: checkForDuplicateNames(qName,
1285: fUnparsedTypeRegistry,
1286: fUnparsedTypeRegistrySub, globalComp,
1287: currSchemaDoc);
1288: } else if (componentType
1289: .equals(SchemaSymbols.ELT_ELEMENT)) {
1290: checkForDuplicateNames(qName,
1291: fUnparsedElementRegistry,
1292: fUnparsedElementRegistrySub,
1293: globalComp, currSchemaDoc);
1294: } else if (componentType
1295: .equals(SchemaSymbols.ELT_GROUP)) {
1296: checkForDuplicateNames(qName,
1297: fUnparsedGroupRegistry,
1298: fUnparsedGroupRegistrySub, globalComp,
1299: currSchemaDoc);
1300: } else if (componentType
1301: .equals(SchemaSymbols.ELT_NOTATION)) {
1302: checkForDuplicateNames(qName,
1303: fUnparsedNotationRegistry,
1304: fUnparsedNotationRegistrySub,
1305: globalComp, currSchemaDoc);
1306: }
1307: }
1308: } // end for
1309:
1310: // now we're done with this one!
1311: DOMUtil.setHidden(currDoc, fHiddenNodes);
1312: // now add the schemas this guy depends on
1313: Vector currSchemaDepends = (Vector) fDependencyMap
1314: .get(currSchemaDoc);
1315: for (int i = 0; i < currSchemaDepends.size(); i++) {
1316: schemasToProcess.push(currSchemaDepends.elementAt(i));
1317: }
1318: } // while
1319:
1320: } // end buildGlobalNameRegistries
1321:
1322: // Beginning at the first schema processing was requested for
1323: // (fRoot), this method
1324: // examines each child (global schema information item) of each
1325: // schema document (and of each <redefine> element)
1326: // corresponding to an XSDocumentInfo object. If the
1327: // readOnly field on that node has not been set, it calls an
1328: // appropriate traverser to traverse it. Once all global decls in
1329: // an XSDocumentInfo object have been traversed, it marks that object
1330: // as traversed (or hidden) in order to avoid infinite loops. It completes
1331: // when it has visited all XSDocumentInfo objects in the
1332: // DependencyMap and marked them as traversed.
1333: protected void traverseSchemas(ArrayList annotationInfo) {
1334: // the process here is very similar to that in
1335: // buildGlobalRegistries, except we can't set our schemas as
1336: // hidden for a second time; so make them all visible again
1337: // first!
1338: setSchemasVisible(fRoot);
1339: Stack schemasToProcess = new Stack();
1340: schemasToProcess.push(fRoot);
1341: while (!schemasToProcess.empty()) {
1342: XSDocumentInfo currSchemaDoc = (XSDocumentInfo) schemasToProcess
1343: .pop();
1344: Element currDoc = currSchemaDoc.fSchemaElement;
1345:
1346: SchemaGrammar currSG = fGrammarBucket
1347: .getGrammar(currSchemaDoc.fTargetNamespace);
1348:
1349: if (DOMUtil.isHidden(currDoc, fHiddenNodes)) {
1350: // must have processed this already!
1351: continue;
1352: }
1353: Element currRoot = currDoc;
1354: boolean sawAnnotation = false;
1355: // traverse this schema's global decls
1356: for (Element globalComp = DOMUtil
1357: .getFirstVisibleChildElement(currRoot, fHiddenNodes); globalComp != null; globalComp = DOMUtil
1358: .getNextVisibleSiblingElement(globalComp,
1359: fHiddenNodes)) {
1360: DOMUtil.setHidden(globalComp, fHiddenNodes);
1361: String componentType = DOMUtil.getLocalName(globalComp);
1362: // includes and imports will not show up here!
1363: if (DOMUtil.getLocalName(globalComp).equals(
1364: SchemaSymbols.ELT_REDEFINE)) {
1365: // use the namespace decls for the redefine, instead of for the parent <schema>
1366: currSchemaDoc
1367: .backupNSSupport((SchemaNamespaceSupport) fRedefine2NSSupport
1368: .get(globalComp));
1369: for (Element redefinedComp = DOMUtil
1370: .getFirstVisibleChildElement(globalComp,
1371: fHiddenNodes); redefinedComp != null; redefinedComp = DOMUtil
1372: .getNextVisibleSiblingElement(
1373: redefinedComp, fHiddenNodes)) {
1374: String redefinedComponentType = DOMUtil
1375: .getLocalName(redefinedComp);
1376: DOMUtil.setHidden(redefinedComp, fHiddenNodes);
1377: if (redefinedComponentType
1378: .equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1379: fAttributeGroupTraverser.traverseGlobal(
1380: redefinedComp, currSchemaDoc,
1381: currSG);
1382: } else if (redefinedComponentType
1383: .equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1384: fComplexTypeTraverser.traverseGlobal(
1385: redefinedComp, currSchemaDoc,
1386: currSG);
1387: } else if (redefinedComponentType
1388: .equals(SchemaSymbols.ELT_GROUP)) {
1389: fGroupTraverser.traverseGlobal(
1390: redefinedComp, currSchemaDoc,
1391: currSG);
1392: } else if (redefinedComponentType
1393: .equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1394: fSimpleTypeTraverser.traverseGlobal(
1395: redefinedComp, currSchemaDoc,
1396: currSG);
1397: }
1398: // annotations will have been processed already; this is now
1399: // unnecessary
1400: //else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
1401: // fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc);
1402: //}
1403: else {
1404: reportSchemaError(
1405: "s4s-elt-must-match.1",
1406: new Object[] {
1407: DOMUtil
1408: .getLocalName(globalComp),
1409: "(annotation | (simpleType | complexType | group | attributeGroup))*",
1410: redefinedComponentType },
1411: redefinedComp);
1412: }
1413: } // end march through <redefine> children
1414: currSchemaDoc.restoreNSSupport();
1415: } else if (componentType
1416: .equals(SchemaSymbols.ELT_ATTRIBUTE)) {
1417: fAttributeTraverser.traverseGlobal(globalComp,
1418: currSchemaDoc, currSG);
1419: } else if (componentType
1420: .equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
1421: fAttributeGroupTraverser.traverseGlobal(globalComp,
1422: currSchemaDoc, currSG);
1423: } else if (componentType
1424: .equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
1425: fComplexTypeTraverser.traverseGlobal(globalComp,
1426: currSchemaDoc, currSG);
1427: } else if (componentType
1428: .equals(SchemaSymbols.ELT_ELEMENT)) {
1429: fElementTraverser.traverseGlobal(globalComp,
1430: currSchemaDoc, currSG);
1431: } else if (componentType
1432: .equals(SchemaSymbols.ELT_GROUP)) {
1433: fGroupTraverser.traverseGlobal(globalComp,
1434: currSchemaDoc, currSG);
1435: } else if (componentType
1436: .equals(SchemaSymbols.ELT_NOTATION)) {
1437: fNotationTraverser.traverse(globalComp,
1438: currSchemaDoc, currSG);
1439: } else if (componentType
1440: .equals(SchemaSymbols.ELT_SIMPLETYPE)) {
1441: fSimpleTypeTraverser.traverseGlobal(globalComp,
1442: currSchemaDoc, currSG);
1443: } else if (componentType
1444: .equals(SchemaSymbols.ELT_ANNOTATION)) {
1445: currSG.addAnnotation(fElementTraverser
1446: .traverseAnnotationDecl(globalComp,
1447: currSchemaDoc.getSchemaAttrs(),
1448: true, currSchemaDoc));
1449: sawAnnotation = true;
1450: } else {
1451: reportSchemaError("s4s-elt-invalid-content.1",
1452: new Object[] { SchemaSymbols.ELT_SCHEMA,
1453: DOMUtil.getLocalName(globalComp) },
1454: globalComp);
1455: }
1456: } // end for
1457:
1458: if (!sawAnnotation) {
1459: String text = DOMUtil.getSyntheticAnnotation(currRoot);
1460: if (text != null) {
1461: currSG.addAnnotation(fElementTraverser
1462: .traverseSyntheticAnnotation(currRoot,
1463: text, currSchemaDoc
1464: .getSchemaAttrs(), true,
1465: currSchemaDoc));
1466: }
1467: }
1468:
1469: /** Collect annotation information for validation. **/
1470: if (annotationInfo != null) {
1471: XSAnnotationInfo info = currSchemaDoc.getAnnotations();
1472: /** Only add annotations to the list if there were any in this document. **/
1473: if (info != null) {
1474: annotationInfo.add(doc2SystemId(currDoc));
1475: annotationInfo.add(info);
1476: }
1477: }
1478: // now we're done with this one!
1479: currSchemaDoc.returnSchemaAttrs();
1480: DOMUtil.setHidden(currDoc, fHiddenNodes);
1481:
1482: // now add the schemas this guy depends on
1483: Vector currSchemaDepends = (Vector) fDependencyMap
1484: .get(currSchemaDoc);
1485: for (int i = 0; i < currSchemaDepends.size(); i++) {
1486: schemasToProcess.push(currSchemaDepends.elementAt(i));
1487: }
1488: } // while
1489: } // end traverseSchemas
1490:
1491: // store whether we have reported an error about that no grammar
1492: // is found for the given namespace uri
1493: private Vector fReportedTNS = null;
1494:
1495: // check whether we need to report an error against the given uri.
1496: // if we have reported an error, then we don't need to report again;
1497: // otherwise we reported the error, and remember this fact.
1498: private final boolean needReportTNSError(String uri) {
1499: if (fReportedTNS == null)
1500: fReportedTNS = new Vector();
1501: else if (fReportedTNS.contains(uri))
1502: return false;
1503: fReportedTNS.addElement(uri);
1504: return true;
1505: }
1506:
1507: private static final String[] COMP_TYPE = {
1508: null, // index 0
1509: "attribute declaration", "attribute group",
1510: "element declaration", "group", "identity constraint",
1511: "notation", "type definition", };
1512:
1513: private static final String[] CIRCULAR_CODES = { "Internal-Error",
1514: "Internal-Error", "src-attribute_group.3",
1515: "e-props-correct.6", "mg-props-correct.2",
1516: "Internal-Error", "Internal-Error", "st-props-correct.2", //or ct-props-correct.3
1517: };
1518:
1519: // since it is forbidden for traversers to talk to each other
1520: // directly (except wen a traverser encounters a local declaration),
1521: // this provides a generic means for a traverser to call
1522: // for the traversal of some declaration. An XSDocumentInfo is
1523: // required because the XSDocumentInfo that the traverser is traversing
1524: // may bear no relation to the one the handler is operating on.
1525: // This method will:
1526: // 1. See if a global definition matching declToTraverse exists;
1527: // 2. if so, determine if there is a path from currSchema to the
1528: // schema document where declToTraverse lives (i.e., do a lookup
1529: // in DependencyMap);
1530: // 3. depending on declType (which will be relevant to step 1 as
1531: // well), call the appropriate traverser with the appropriate
1532: // XSDocumentInfo object.
1533: // This method returns whatever the traverser it called returned;
1534: // this will be an Object of some kind
1535: // that lives in the Grammar.
1536: protected Object getGlobalDecl(XSDocumentInfo currSchema,
1537: int declType, QName declToTraverse, Element elmNode) {
1538:
1539: if (DEBUG_NODE_POOL) {
1540: System.out.println("TRAVERSE_GL: "
1541: + declToTraverse.toString());
1542: }
1543: // from the schema spec, all built-in types are present in all schemas,
1544: // so if the requested component is a type, and could be found in the
1545: // default schema grammar, we should return that type.
1546: // otherwise (since we would support user-defined schema grammar) we'll
1547: // use the normal way to get the decl
1548: if (declToTraverse.uri != null
1549: && declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
1550: if (declType == TYPEDECL_TYPE) {
1551: Object retObj = SchemaGrammar.SG_SchemaNS
1552: .getGlobalTypeDecl(declToTraverse.localpart);
1553: if (retObj != null)
1554: return retObj;
1555: }
1556: }
1557:
1558: // now check whether this document can access the requsted namespace
1559: if (!currSchema.isAllowedNS(declToTraverse.uri)) {
1560: // cannot get to this schema from the one containing the requesting decl
1561: if (currSchema.needReportTNSError(declToTraverse.uri)) {
1562: String code = declToTraverse.uri == null ? "src-resolve.4.1"
1563: : "src-resolve.4.2";
1564: reportSchemaError(code, new Object[] {
1565: fDoc2SystemId.get(currSchema.fSchemaElement),
1566: declToTraverse.uri, declToTraverse.rawname },
1567: elmNode);
1568: }
1569: return null;
1570: }
1571:
1572: // check whether there is grammar for the requested namespace
1573: SchemaGrammar sGrammar = fGrammarBucket
1574: .getGrammar(declToTraverse.uri);
1575: if (sGrammar == null) {
1576: if (needReportTNSError(declToTraverse.uri))
1577: reportSchemaError("src-resolve", new Object[] {
1578: declToTraverse.rawname, COMP_TYPE[declType] },
1579: elmNode);
1580: return null;
1581: }
1582:
1583: // if there is such grammar, check whether the requested component is in the grammar
1584: Object retObj = null;
1585: switch (declType) {
1586: case ATTRIBUTE_TYPE:
1587: retObj = sGrammar
1588: .getGlobalAttributeDecl(declToTraverse.localpart);
1589: break;
1590: case ATTRIBUTEGROUP_TYPE:
1591: retObj = sGrammar
1592: .getGlobalAttributeGroupDecl(declToTraverse.localpart);
1593: break;
1594: case ELEMENT_TYPE:
1595: retObj = sGrammar
1596: .getGlobalElementDecl(declToTraverse.localpart);
1597: break;
1598: case GROUP_TYPE:
1599: retObj = sGrammar
1600: .getGlobalGroupDecl(declToTraverse.localpart);
1601: break;
1602: case IDENTITYCONSTRAINT_TYPE:
1603: retObj = sGrammar
1604: .getIDConstraintDecl(declToTraverse.localpart);
1605: break;
1606: case NOTATION_TYPE:
1607: retObj = sGrammar
1608: .getGlobalNotationDecl(declToTraverse.localpart);
1609: break;
1610: case TYPEDECL_TYPE:
1611: retObj = sGrammar
1612: .getGlobalTypeDecl(declToTraverse.localpart);
1613: break;
1614: }
1615:
1616: // if the component is parsed, return it
1617: if (retObj != null)
1618: return retObj;
1619:
1620: XSDocumentInfo schemaWithDecl = null;
1621: Element decl = null;
1622: XSDocumentInfo declDoc = null;
1623:
1624: // the component is not parsed, try to find a DOM element for it
1625: String declKey = declToTraverse.uri == null ? ","
1626: + declToTraverse.localpart : declToTraverse.uri + ","
1627: + declToTraverse.localpart;
1628: switch (declType) {
1629: case ATTRIBUTE_TYPE:
1630: decl = (Element) fUnparsedAttributeRegistry.get(declKey);
1631: declDoc = (XSDocumentInfo) fUnparsedAttributeRegistrySub
1632: .get(declKey);
1633: break;
1634: case ATTRIBUTEGROUP_TYPE:
1635: decl = (Element) fUnparsedAttributeGroupRegistry
1636: .get(declKey);
1637: declDoc = (XSDocumentInfo) fUnparsedAttributeGroupRegistrySub
1638: .get(declKey);
1639: break;
1640: case ELEMENT_TYPE:
1641: decl = (Element) fUnparsedElementRegistry.get(declKey);
1642: declDoc = (XSDocumentInfo) fUnparsedElementRegistrySub
1643: .get(declKey);
1644: break;
1645: case GROUP_TYPE:
1646: decl = (Element) fUnparsedGroupRegistry.get(declKey);
1647: declDoc = (XSDocumentInfo) fUnparsedGroupRegistrySub
1648: .get(declKey);
1649: break;
1650: case IDENTITYCONSTRAINT_TYPE:
1651: decl = (Element) fUnparsedIdentityConstraintRegistry
1652: .get(declKey);
1653: declDoc = (XSDocumentInfo) fUnparsedIdentityConstraintRegistrySub
1654: .get(declKey);
1655: break;
1656: case NOTATION_TYPE:
1657: decl = (Element) fUnparsedNotationRegistry.get(declKey);
1658: declDoc = (XSDocumentInfo) fUnparsedNotationRegistrySub
1659: .get(declKey);
1660: break;
1661: case TYPEDECL_TYPE:
1662: decl = (Element) fUnparsedTypeRegistry.get(declKey);
1663: declDoc = (XSDocumentInfo) fUnparsedTypeRegistrySub
1664: .get(declKey);
1665: break;
1666: default:
1667: reportSchemaError(
1668: "Internal-Error",
1669: new Object[] { "XSDHandler asked to locate component of type "
1670: + declType
1671: + "; it does not recognize this type!" },
1672: elmNode);
1673: }
1674:
1675: // no DOM element found, so the component can't be located
1676: if (decl == null) {
1677: reportSchemaError("src-resolve", new Object[] {
1678: declToTraverse.rawname, COMP_TYPE[declType] },
1679: elmNode);
1680: return null;
1681: }
1682:
1683: // get the schema doc containing the component to be parsed
1684: // it should always return non-null value, but since null-checking
1685: // comes for free, let's be safe and check again
1686: schemaWithDecl = findXSDocumentForDecl(currSchema, decl,
1687: declDoc);
1688: if (schemaWithDecl == null) {
1689: // cannot get to this schema from the one containing the requesting decl
1690: String code = declToTraverse.uri == null ? "src-resolve.4.1"
1691: : "src-resolve.4.2";
1692: reportSchemaError(code, new Object[] {
1693: fDoc2SystemId.get(currSchema.fSchemaElement),
1694: declToTraverse.uri, declToTraverse.rawname },
1695: elmNode);
1696: return null;
1697: }
1698: // a component is hidden, meaning either it's traversed, or being traversed.
1699: // but we didn't find it in the grammar, so it's the latter case, and
1700: // a circular reference. error!
1701: if (DOMUtil.isHidden(decl, fHiddenNodes)) {
1702: String code = CIRCULAR_CODES[declType];
1703: if (declType == TYPEDECL_TYPE) {
1704: if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil
1705: .getLocalName(decl)))
1706: code = "ct-props-correct.3";
1707: }
1708: // decl must not be null if we're here...
1709: reportSchemaError(code,
1710: new Object[] { declToTraverse.prefix + ":"
1711: + declToTraverse.localpart }, elmNode);
1712: return null;
1713: }
1714:
1715: DOMUtil.setHidden(decl, fHiddenNodes);
1716: SchemaNamespaceSupport nsSupport = null;
1717: // if the parent is <redefine> use the namespace delcs for it.
1718: Element parent = DOMUtil.getParent(decl);
1719: if (DOMUtil.getLocalName(parent).equals(
1720: SchemaSymbols.ELT_REDEFINE))
1721: nsSupport = (SchemaNamespaceSupport) fRedefine2NSSupport
1722: .get(parent);
1723: // back up the current SchemaNamespaceSupport, because we need to provide
1724: // a fresh one to the traverseGlobal methods.
1725: schemaWithDecl.backupNSSupport(nsSupport);
1726:
1727: // traverse the referenced global component
1728: switch (declType) {
1729: case ATTRIBUTE_TYPE:
1730: retObj = fAttributeTraverser.traverseGlobal(decl,
1731: schemaWithDecl, sGrammar);
1732: break;
1733: case ATTRIBUTEGROUP_TYPE:
1734: retObj = fAttributeGroupTraverser.traverseGlobal(decl,
1735: schemaWithDecl, sGrammar);
1736: break;
1737: case ELEMENT_TYPE:
1738: retObj = fElementTraverser.traverseGlobal(decl,
1739: schemaWithDecl, sGrammar);
1740: break;
1741: case GROUP_TYPE:
1742: retObj = fGroupTraverser.traverseGlobal(decl,
1743: schemaWithDecl, sGrammar);
1744: break;
1745: case IDENTITYCONSTRAINT_TYPE:
1746: // identity constraints should have been parsed already...
1747: // we should never get here
1748: retObj = null;
1749: break;
1750: case NOTATION_TYPE:
1751: retObj = fNotationTraverser.traverse(decl, schemaWithDecl,
1752: sGrammar);
1753: break;
1754: case TYPEDECL_TYPE:
1755: if (DOMUtil.getLocalName(decl).equals(
1756: SchemaSymbols.ELT_COMPLEXTYPE))
1757: retObj = fComplexTypeTraverser.traverseGlobal(decl,
1758: schemaWithDecl, sGrammar);
1759: else
1760: retObj = fSimpleTypeTraverser.traverseGlobal(decl,
1761: schemaWithDecl, sGrammar);
1762: }
1763:
1764: // restore the previous SchemaNamespaceSupport, so that the caller can get
1765: // proper namespace binding.
1766: schemaWithDecl.restoreNSSupport();
1767:
1768: return retObj;
1769: } // getGlobalDecl(XSDocumentInfo, int, QName): Object
1770:
1771: // This method determines whether there is a group
1772: // (attributeGroup) which the given one has redefined by
1773: // restriction. If so, it returns it; else it returns null.
1774: // @param type: whether what's been redefined is an
1775: // attributeGroup or a group;
1776: // @param name: the QName of the component doing the redefining.
1777: // @param currSchema: schema doc in which the redefining component lives.
1778: // @return: Object representing decl redefined if present, null
1779: // otherwise.
1780: Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name,
1781: XSDocumentInfo currSchema, Element elmNode) {
1782: String realName = name.uri != null ? name.uri + ","
1783: + name.localpart : "," + name.localpart;
1784: String nameToFind = null;
1785: switch (type) {
1786: case ATTRIBUTEGROUP_TYPE:
1787: nameToFind = (String) fRedefinedRestrictedAttributeGroupRegistry
1788: .get(realName);
1789: break;
1790: case GROUP_TYPE:
1791: nameToFind = (String) fRedefinedRestrictedGroupRegistry
1792: .get(realName);
1793: break;
1794: default:
1795: return null;
1796: }
1797: if (nameToFind == null)
1798: return null;
1799: int commaPos = nameToFind.indexOf(",");
1800: QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING,
1801: nameToFind.substring(commaPos + 1), nameToFind
1802: .substring(commaPos), (commaPos == 0) ? null
1803: : nameToFind.substring(0, commaPos));
1804: Object retObj = getGlobalDecl(currSchema, type, qNameToFind,
1805: elmNode);
1806: if (retObj == null) {
1807: switch (type) {
1808: case ATTRIBUTEGROUP_TYPE:
1809: reportSchemaError("src-redefine.7.2.1",
1810: new Object[] { name.localpart }, elmNode);
1811: break;
1812: case GROUP_TYPE:
1813: reportSchemaError("src-redefine.6.2.1",
1814: new Object[] { name.localpart }, elmNode);
1815: break;
1816: }
1817: return null;
1818: }
1819: return retObj;
1820: } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object
1821:
1822: // Since ID constraints can occur in local elements, unless we
1823: // wish to completely traverse all our DOM trees looking for ID
1824: // constraints while we're building our global name registries,
1825: // which seems terribly inefficient, we need to resolve keyrefs
1826: // after all parsing is complete. This we can simply do by running through
1827: // fIdentityConstraintRegistry and calling traverseKeyRef on all
1828: // of the KeyRef nodes. This unfortunately removes this knowledge
1829: // from the elementTraverser class (which must ignore keyrefs),
1830: // but there seems to be no efficient way around this...
1831: protected void resolveKeyRefs() {
1832: for (int i = 0; i < fKeyrefStackPos; i++) {
1833: XSDocumentInfo keyrefSchemaDoc = fKeyrefsMapXSDocumentInfo[i];
1834: keyrefSchemaDoc.fNamespaceSupport.makeGlobal();
1835: keyrefSchemaDoc.fNamespaceSupport
1836: .setEffectiveContext(fKeyrefNamespaceContext[i]);
1837: SchemaGrammar keyrefGrammar = fGrammarBucket
1838: .getGrammar(keyrefSchemaDoc.fTargetNamespace);
1839: // need to set <keyref> to hidden before traversing it,
1840: // because it has global scope
1841: DOMUtil.setHidden(fKeyrefs[i], fHiddenNodes);
1842: fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i],
1843: keyrefSchemaDoc, keyrefGrammar);
1844: }
1845: } // end resolveKeyRefs
1846:
1847: // an accessor method. Just makes sure callers
1848: // who want the Identity constraint registry vaguely know what they're about.
1849: protected Hashtable getIDRegistry() {
1850: return fUnparsedIdentityConstraintRegistry;
1851: }
1852:
1853: // an accessor method.
1854: protected Hashtable getIDRegistry_sub() {
1855: return fUnparsedIdentityConstraintRegistrySub;
1856: }
1857:
1858: // This method squirrels away <keyref> declarations--along with the element
1859: // decls and namespace bindings they might find handy.
1860: protected void storeKeyRef(Element keyrefToStore,
1861: XSDocumentInfo schemaDoc, XSElementDecl currElemDecl) {
1862: String keyrefName = DOMUtil.getAttrValue(keyrefToStore,
1863: SchemaSymbols.ATT_NAME);
1864: if (keyrefName.length() != 0) {
1865: String keyrefQName = schemaDoc.fTargetNamespace == null ? ","
1866: + keyrefName
1867: : schemaDoc.fTargetNamespace + "," + keyrefName;
1868: checkForDuplicateNames(keyrefQName,
1869: fUnparsedIdentityConstraintRegistry,
1870: fUnparsedIdentityConstraintRegistrySub,
1871: keyrefToStore, schemaDoc);
1872: }
1873: // now set up all the registries we'll need...
1874:
1875: // check array sizes
1876: if (fKeyrefStackPos == fKeyrefs.length) {
1877: Element[] elemArray = new Element[fKeyrefStackPos
1878: + INC_KEYREF_STACK_AMOUNT];
1879: System
1880: .arraycopy(fKeyrefs, 0, elemArray, 0,
1881: fKeyrefStackPos);
1882: fKeyrefs = elemArray;
1883: XSElementDecl[] declArray = new XSElementDecl[fKeyrefStackPos
1884: + INC_KEYREF_STACK_AMOUNT];
1885: System.arraycopy(fKeyrefElems, 0, declArray, 0,
1886: fKeyrefStackPos);
1887: fKeyrefElems = declArray;
1888: String[][] stringArray = new String[fKeyrefStackPos
1889: + INC_KEYREF_STACK_AMOUNT][];
1890: System.arraycopy(fKeyrefNamespaceContext, 0, stringArray,
1891: 0, fKeyrefStackPos);
1892: fKeyrefNamespaceContext = stringArray;
1893:
1894: XSDocumentInfo[] xsDocumentInfo = new XSDocumentInfo[fKeyrefStackPos
1895: + INC_KEYREF_STACK_AMOUNT];
1896: System.arraycopy(fKeyrefsMapXSDocumentInfo, 0,
1897: xsDocumentInfo, 0, fKeyrefStackPos);
1898: fKeyrefsMapXSDocumentInfo = xsDocumentInfo;
1899:
1900: }
1901: fKeyrefs[fKeyrefStackPos] = keyrefToStore;
1902: fKeyrefElems[fKeyrefStackPos] = currElemDecl;
1903: fKeyrefNamespaceContext[fKeyrefStackPos] = schemaDoc.fNamespaceSupport
1904: .getEffectiveLocalContext();
1905:
1906: fKeyrefsMapXSDocumentInfo[fKeyrefStackPos++] = schemaDoc;
1907: } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void
1908:
1909: /**
1910: * resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver),
1911: * and if it was succefully resolved getting the schema Document.
1912: * @param desc
1913: * @param mustResolve
1914: * @param referElement
1915: * @return A schema Element or null.
1916: */
1917: private Element resolveSchema(XSDDescription desc,
1918: boolean mustResolve, Element referElement, boolean usePairs) {
1919: XMLInputSource schemaSource = null;
1920: try {
1921: Hashtable pairs = usePairs ? fLocationPairs : EMPTY_TABLE;
1922: schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs,
1923: fEntityResolver);
1924: } catch (IOException ex) {
1925: if (mustResolve) {
1926: reportSchemaError("schema_reference.4",
1927: new Object[] { desc.getLocationHints()[0] },
1928: referElement);
1929: } else {
1930: reportSchemaWarning("schema_reference.4",
1931: new Object[] { desc.getLocationHints()[0] },
1932: referElement);
1933: }
1934: }
1935: if (schemaSource instanceof DOMInputSource) {
1936: fHiddenNodes.clear();
1937: Node node = ((DOMInputSource) schemaSource).getNode();
1938:
1939: if (node instanceof Document) {
1940: return DOMUtil.getRoot((Document) node);
1941: } else if (node instanceof Element) {
1942: return (Element) node;
1943: } else {
1944: return null;
1945: }
1946: } // DOMInputSource
1947: else if (schemaSource instanceof SAXInputSource) {
1948: XMLReader parser = ((SAXInputSource) schemaSource)
1949: .getXMLReader();
1950: InputSource inputSource = ((SAXInputSource) schemaSource)
1951: .getInputSource();
1952: boolean namespacePrefixes = false;
1953: if (parser != null) {
1954: try {
1955: namespacePrefixes = parser
1956: .getFeature(NAMESPACE_PREFIXES);
1957: } catch (SAXException se) {
1958: }
1959: } else {
1960: try {
1961: parser = XMLReaderFactory.createXMLReader();
1962: }
1963: // If something went wrong with the factory
1964: // just use our own SAX parser.
1965: catch (SAXException se) {
1966: parser = new SAXParser();
1967: }
1968: try {
1969: parser.setFeature(NAMESPACE_PREFIXES, true);
1970: namespacePrefixes = true;
1971: } catch (SAXException se) {
1972: }
1973: }
1974: // If XML names and Namespace URIs are already internalized we
1975: // can avoid running them through the SymbolTable.
1976: boolean stringsInternalized = false;
1977: try {
1978: stringsInternalized = parser
1979: .getFeature(STRING_INTERNING);
1980: } catch (SAXException exc) {
1981: // The feature isn't recognized or getting it is not supported.
1982: // In either case, assume that strings are not internalized.
1983: }
1984: if (fXSContentHandler == null) {
1985: fXSContentHandler = new SchemaContentHandler();
1986: }
1987: fXSContentHandler.reset(fSchemaParser, fSymbolTable,
1988: namespacePrefixes, stringsInternalized);
1989: parser.setContentHandler(fXSContentHandler);
1990: parser.setErrorHandler(fErrorReporter.getSAXErrorHandler());
1991: try {
1992: parser.parse(inputSource);
1993: } catch (SAXException se) {
1994: return null;
1995: } catch (IOException ioe) {
1996: return null;
1997: }
1998: Document root = fXSContentHandler.getDocument();
1999: if (root == null) {
2000: // something went wrong right off the hop
2001: return null;
2002: }
2003: return DOMUtil.getRoot(root);
2004: }
2005: return getSchemaDocument(desc.getTargetNamespace(),
2006: schemaSource, mustResolve, desc.getContextType(),
2007: referElement);
2008: } // getSchema(String, String, String, boolean, short): Document
2009:
2010: /**
2011: * getSchemaDocument method uses XMLInputSource to parse a schema document.
2012: * @param schemaNamespace
2013: * @param schemaSource
2014: * @param mustResolve
2015: * @param referType
2016: * @param referElement
2017: * @return A schema Element.
2018: */
2019: private Element getSchemaDocument(String schemaNamespace,
2020: XMLInputSource schemaSource, boolean mustResolve,
2021: short referType, Element referElement) {
2022:
2023: boolean hasInput = true;
2024: // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc.
2025: Element schemaElement = null;
2026: try {
2027: // when the system id and byte stream and character stream
2028: // of the input source are all null, it's
2029: // impossible to find the schema document. so we skip in
2030: // this case. otherwise we'll receive some NPE or
2031: // file not found errors. but schemaHint=="" is perfectly
2032: // legal for import.
2033: if (schemaSource != null
2034: && (schemaSource.getSystemId() != null
2035: || schemaSource.getByteStream() != null || schemaSource
2036: .getCharacterStream() != null)) {
2037:
2038: // When the system id of the input source is used, first try to
2039: // expand it, and check whether the same document has been
2040: // parsed before. If so, return the document corresponding to
2041: // that system id.
2042: XSDKey key = null;
2043: String schemaId = null;
2044: if (referType != XSDDescription.CONTEXT_PREPARSE) {
2045: schemaId = XMLEntityManager.expandSystemId(
2046: schemaSource.getSystemId(), schemaSource
2047: .getBaseSystemId(), false);
2048: key = new XSDKey(schemaId, referType,
2049: schemaNamespace);
2050: if ((schemaElement = (Element) fTraversed.get(key)) != null) {
2051: fLastSchemaWasDuplicate = true;
2052: return schemaElement;
2053: }
2054: }
2055:
2056: fSchemaParser.parse(schemaSource);
2057: schemaElement = fSchemaParser.getDocument2() == null ? null
2058: : DOMUtil.getRoot(fSchemaParser.getDocument2());
2059:
2060: // now we need to store the mapping information from system id
2061: // to the document. also from the document to the system id.
2062: if (key != null)
2063: fTraversed.put(key, schemaElement);
2064: if (schemaId != null)
2065: fDoc2SystemId.put(schemaElement, schemaId);
2066: fLastSchemaWasDuplicate = false;
2067: return schemaElement;
2068: } else {
2069: hasInput = false;
2070: }
2071: } catch (IOException ex) {
2072: }
2073:
2074: // either an error occured (exception), or empty input source was
2075: // returned, we need to report an error or a warning
2076: if (mustResolve) {
2077: if (hasInput) {
2078: reportSchemaError("schema_reference.4",
2079: new Object[] { schemaSource.getSystemId() },
2080: referElement);
2081: } else {
2082: reportSchemaError("schema_reference.4",
2083: new Object[] { schemaSource == null ? ""
2084: : schemaSource.getSystemId() },
2085: referElement);
2086: }
2087: } else if (hasInput) {
2088: reportSchemaWarning("schema_reference.4",
2089: new Object[] { schemaSource.getSystemId() },
2090: referElement);
2091: }
2092:
2093: fLastSchemaWasDuplicate = false;
2094: return null;
2095: } // getSchema(String, XMLInputSource, boolean, boolean): Document
2096:
2097: // initialize all the traversers.
2098: // this should only need to be called once during the construction
2099: // of this object; it creates the traversers that will be used to
2100:
2101: // construct schemaGrammars.
2102: private void createTraversers() {
2103: fAttributeChecker = new XSAttributeChecker(this );
2104: fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this ,
2105: fAttributeChecker);
2106: fAttributeTraverser = new XSDAttributeTraverser(this ,
2107: fAttributeChecker);
2108: fComplexTypeTraverser = new XSDComplexTypeTraverser(this ,
2109: fAttributeChecker);
2110: fElementTraverser = new XSDElementTraverser(this ,
2111: fAttributeChecker);
2112: fGroupTraverser = new XSDGroupTraverser(this , fAttributeChecker);
2113: fKeyrefTraverser = new XSDKeyrefTraverser(this ,
2114: fAttributeChecker);
2115: fNotationTraverser = new XSDNotationTraverser(this ,
2116: fAttributeChecker);
2117: fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this ,
2118: fAttributeChecker);
2119: fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this ,
2120: fAttributeChecker);
2121: fWildCardTraverser = new XSDWildcardTraverser(this ,
2122: fAttributeChecker);
2123: } // createTraversers()
2124:
2125: // before parsing a schema, need to clear registries associated with
2126: // parsing schemas
2127: void prepareForParse() {
2128: fTraversed.clear();
2129: fDoc2SystemId.clear();
2130: fHiddenNodes.clear();
2131: fLastSchemaWasDuplicate = false;
2132: }
2133:
2134: // before traversing a schema's parse tree, need to reset all traversers and
2135: // clear all registries
2136: void prepareForTraverse() {
2137: fUnparsedAttributeRegistry.clear();
2138: fUnparsedAttributeGroupRegistry.clear();
2139: fUnparsedElementRegistry.clear();
2140: fUnparsedGroupRegistry.clear();
2141: fUnparsedIdentityConstraintRegistry.clear();
2142: fUnparsedNotationRegistry.clear();
2143: fUnparsedTypeRegistry.clear();
2144:
2145: fUnparsedAttributeRegistrySub.clear();
2146: fUnparsedAttributeGroupRegistrySub.clear();
2147: fUnparsedElementRegistrySub.clear();
2148: fUnparsedGroupRegistrySub.clear();
2149: fUnparsedIdentityConstraintRegistrySub.clear();
2150: fUnparsedNotationRegistrySub.clear();
2151: fUnparsedTypeRegistrySub.clear();
2152:
2153: fXSDocumentInfoRegistry.clear();
2154: fDependencyMap.clear();
2155: fDoc2XSDocumentMap.clear();
2156: fRedefine2XSDMap.clear();
2157: fRedefine2NSSupport.clear();
2158: fAllTNSs.removeAllElements();
2159: fImportMap.clear();
2160: fRoot = null;
2161:
2162: // clear local element stack
2163: for (int i = 0; i < fLocalElemStackPos; i++) {
2164: fParticle[i] = null;
2165: fLocalElementDecl[i] = null;
2166: fLocalElementDecl_schema[i] = null;
2167: fLocalElemNamespaceContext[i] = null;
2168: }
2169: fLocalElemStackPos = 0;
2170:
2171: // and do same for keyrefs.
2172: for (int i = 0; i < fKeyrefStackPos; i++) {
2173: fKeyrefs[i] = null;
2174: fKeyrefElems[i] = null;
2175: fKeyrefNamespaceContext[i] = null;
2176: fKeyrefsMapXSDocumentInfo[i] = null;
2177: }
2178: fKeyrefStackPos = 0;
2179:
2180: // create traversers if necessary
2181: if (fAttributeChecker == null) {
2182: createTraversers();
2183: }
2184:
2185: // reset traversers
2186: fAttributeChecker.reset(fSymbolTable);
2187: fAttributeGroupTraverser.reset(fSymbolTable,
2188: fValidateAnnotations);
2189: fAttributeTraverser.reset(fSymbolTable, fValidateAnnotations);
2190: fComplexTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
2191: fElementTraverser.reset(fSymbolTable, fValidateAnnotations);
2192: fGroupTraverser.reset(fSymbolTable, fValidateAnnotations);
2193: fKeyrefTraverser.reset(fSymbolTable, fValidateAnnotations);
2194: fNotationTraverser.reset(fSymbolTable, fValidateAnnotations);
2195: fSimpleTypeTraverser.reset(fSymbolTable, fValidateAnnotations);
2196: fUniqueOrKeyTraverser.reset(fSymbolTable, fValidateAnnotations);
2197: fWildCardTraverser.reset(fSymbolTable, fValidateAnnotations);
2198:
2199: fRedefinedRestrictedAttributeGroupRegistry.clear();
2200: fRedefinedRestrictedGroupRegistry.clear();
2201: }
2202:
2203: public void setDeclPool(XSDeclarationPool declPool) {
2204: fDeclPool = declPool;
2205: }
2206:
2207: public void reset(XMLComponentManager componentManager) {
2208:
2209: // set symbol table
2210: fSymbolTable = (SymbolTable) componentManager
2211: .getProperty(SYMBOL_TABLE);
2212:
2213: //set entity resolver
2214: fEntityResolver = (XMLEntityResolver) componentManager
2215: .getProperty(ENTITY_MANAGER);
2216: XMLEntityResolver er = (XMLEntityResolver) componentManager
2217: .getProperty(ENTITY_RESOLVER);
2218: if (er != null)
2219: fSchemaParser.setEntityResolver(er);
2220:
2221: // set error reporter
2222: fErrorReporter = (XMLErrorReporter) componentManager
2223: .getProperty(ERROR_REPORTER);
2224: try {
2225: XMLErrorHandler currErrorHandler = fErrorReporter
2226: .getErrorHandler();
2227: // Setting a parser property can be much more expensive
2228: // than checking its value. Don't set the ERROR_HANDLER
2229: // property unless it's actually changed.
2230: if (currErrorHandler != fSchemaParser
2231: .getProperty(ERROR_HANDLER)) {
2232: fSchemaParser.setProperty(ERROR_HANDLER,
2233: (currErrorHandler != null) ? currErrorHandler
2234: : new DefaultErrorHandler());
2235: if (fAnnotationValidator != null) {
2236: fAnnotationValidator
2237: .setProperty(
2238: ERROR_HANDLER,
2239: (currErrorHandler != null) ? currErrorHandler
2240: : new DefaultErrorHandler());
2241: }
2242: }
2243: } catch (XMLConfigurationException e) {
2244: }
2245:
2246: try {
2247: fValidateAnnotations = componentManager
2248: .getFeature(VALIDATE_ANNOTATIONS);
2249: } catch (XMLConfigurationException e) {
2250: fValidateAnnotations = false;
2251: }
2252:
2253: try {
2254: fHonourAllSchemaLocations = componentManager
2255: .getFeature(HONOUR_ALL_SCHEMALOCATIONS);
2256: } catch (XMLConfigurationException e) {
2257: fHonourAllSchemaLocations = false;
2258: }
2259:
2260: try {
2261: fSchemaParser.setFeature(CONTINUE_AFTER_FATAL_ERROR,
2262: fErrorReporter
2263: .getFeature(CONTINUE_AFTER_FATAL_ERROR));
2264: } catch (XMLConfigurationException e) {
2265: }
2266:
2267: try {
2268: fSchemaParser.setFeature(ALLOW_JAVA_ENCODINGS,
2269: componentManager.getFeature(ALLOW_JAVA_ENCODINGS));
2270: } catch (XMLConfigurationException e) {
2271: }
2272: try {
2273: fSchemaParser
2274: .setFeature(
2275: STANDARD_URI_CONFORMANT_FEATURE,
2276: componentManager
2277: .getFeature(STANDARD_URI_CONFORMANT_FEATURE));
2278: } catch (XMLConfigurationException e) {
2279: }
2280:
2281: try {
2282: fGrammarPool = (XMLGrammarPool) componentManager
2283: .getProperty(XMLGRAMMAR_POOL);
2284: } catch (XMLConfigurationException e) {
2285: fGrammarPool = null;
2286: }
2287: // security features
2288: try {
2289: fSchemaParser.setFeature(DISALLOW_DOCTYPE, componentManager
2290: .getFeature(DISALLOW_DOCTYPE));
2291: } catch (XMLConfigurationException e) {
2292: }
2293: try {
2294: Object security = componentManager
2295: .getProperty(SECURITY_MANAGER);
2296: if (security != null) {
2297: fSchemaParser.setProperty(SECURITY_MANAGER, security);
2298: }
2299: } catch (XMLConfigurationException e) {
2300: }
2301:
2302: } // reset(XMLComponentManager)
2303:
2304: /**
2305: * Traverse all the deferred local elements. This method should be called
2306: * by traverseSchemas after we've done with all the global declarations.
2307: */
2308: void traverseLocalElements() {
2309: fElementTraverser.fDeferTraversingLocalElements = false;
2310:
2311: for (int i = 0; i < fLocalElemStackPos; i++) {
2312: Element currElem = fLocalElementDecl[i];
2313: //XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem));
2314: //XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getRoot(DOMUtil.getDocument(currElem)));
2315: XSDocumentInfo currSchema = fLocalElementDecl_schema[i];
2316: SchemaGrammar currGrammar = fGrammarBucket
2317: .getGrammar(currSchema.fTargetNamespace);
2318: fElementTraverser.traverseLocal(fParticle[i], currElem,
2319: currSchema, currGrammar, fAllContext[i],
2320: fParent[i], fLocalElemNamespaceContext[i]);
2321: // If it's an empty particle, remove it from the containing component.
2322: if (fParticle[i].fType == XSParticleDecl.PARTICLE_EMPTY) {
2323: XSModelGroupImpl group = null;
2324: if (fParent[i] instanceof XSComplexTypeDecl) {
2325: XSParticle p = ((XSComplexTypeDecl) fParent[i])
2326: .getParticle();
2327: if (p != null)
2328: group = (XSModelGroupImpl) p.getTerm();
2329: } else {
2330: group = ((XSGroupDecl) fParent[i]).fModelGroup;
2331: }
2332: if (group != null)
2333: removeParticle(group, fParticle[i]);
2334: }
2335: }
2336: }
2337:
2338: private boolean removeParticle(XSModelGroupImpl group,
2339: XSParticleDecl particle) {
2340: XSParticleDecl member;
2341: for (int i = 0; i < group.fParticleCount; i++) {
2342: member = group.fParticles[i];
2343: if (member == particle) {
2344: for (int j = i; j < group.fParticleCount - 1; j++)
2345: group.fParticles[j] = group.fParticles[j + 1];
2346: group.fParticleCount--;
2347: return true;
2348: }
2349: if (member.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
2350: if (removeParticle((XSModelGroupImpl) member.fValue,
2351: particle))
2352: return true;
2353: }
2354: }
2355: return false;
2356: }
2357:
2358: // the purpose of this method is to keep up-to-date structures
2359: // we'll need for the feferred traversal of local elements.
2360: void fillInLocalElemInfo(Element elmDecl, XSDocumentInfo schemaDoc,
2361: int allContextFlags, XSObject parent,
2362: XSParticleDecl particle) {
2363:
2364: // if the stack is full, increase the size
2365: if (fParticle.length == fLocalElemStackPos) {
2366: // increase size
2367: XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos
2368: + INC_STACK_SIZE];
2369: System.arraycopy(fParticle, 0, newStackP, 0,
2370: fLocalElemStackPos);
2371: fParticle = newStackP;
2372: Element[] newStackE = new Element[fLocalElemStackPos
2373: + INC_STACK_SIZE];
2374: System.arraycopy(fLocalElementDecl, 0, newStackE, 0,
2375: fLocalElemStackPos);
2376: fLocalElementDecl = newStackE;
2377: XSDocumentInfo[] newStackE_schema = new XSDocumentInfo[fLocalElemStackPos
2378: + INC_STACK_SIZE];
2379: System.arraycopy(fLocalElementDecl_schema, 0,
2380: newStackE_schema, 0, fLocalElemStackPos);
2381: fLocalElementDecl_schema = newStackE_schema;
2382: int[] newStackI = new int[fLocalElemStackPos
2383: + INC_STACK_SIZE];
2384: System.arraycopy(fAllContext, 0, newStackI, 0,
2385: fLocalElemStackPos);
2386: fAllContext = newStackI;
2387: XSObject[] newStackC = new XSObject[fLocalElemStackPos
2388: + INC_STACK_SIZE];
2389: System.arraycopy(fParent, 0, newStackC, 0,
2390: fLocalElemStackPos);
2391: fParent = newStackC;
2392: String[][] newStackN = new String[fLocalElemStackPos
2393: + INC_STACK_SIZE][];
2394: System.arraycopy(fLocalElemNamespaceContext, 0, newStackN,
2395: 0, fLocalElemStackPos);
2396: fLocalElemNamespaceContext = newStackN;
2397: }
2398:
2399: fParticle[fLocalElemStackPos] = particle;
2400: fLocalElementDecl[fLocalElemStackPos] = elmDecl;
2401: fLocalElementDecl_schema[fLocalElemStackPos] = schemaDoc;
2402: fAllContext[fLocalElemStackPos] = allContextFlags;
2403: fParent[fLocalElemStackPos] = parent;
2404: fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport
2405: .getEffectiveLocalContext();
2406: } // end fillInLocalElemInfo(...)
2407:
2408: /** This method makes sure that
2409: * if this component is being redefined that it lives in the
2410: * right schema. It then renames the component correctly. If it
2411: * detects a collision--a duplicate definition--then it complains.
2412: * Note that redefines must be handled carefully: if there
2413: * is a collision, it may be because we're redefining something we know about
2414: * or because we've found the thing we're redefining.
2415: */
2416: void checkForDuplicateNames(String qName, Hashtable registry,
2417: Hashtable registry_sub, Element currComp,
2418: XSDocumentInfo currSchema) {
2419: Object objElem = null;
2420: // REVISIT: when we add derivation checking, we'll have to make
2421: // sure that ID constraint collisions don't necessarily result in error messages.
2422: if ((objElem = registry.get(qName)) == null) {
2423: // just add it in!
2424: registry.put(qName, currComp);
2425: registry_sub.put(qName, currSchema);
2426:
2427: } else {
2428: Element collidingElem = (Element) objElem;
2429: XSDocumentInfo collidingElemSchema = (XSDocumentInfo) registry_sub
2430: .get(qName);
2431: if (collidingElem == currComp)
2432: return;
2433: Element elemParent = null;
2434: XSDocumentInfo redefinedSchema = null;
2435: // case where we've collided with a redefining element
2436: // (the parent of the colliding element is a redefine)
2437: boolean collidedWithRedefine = true;
2438: if ((DOMUtil.getLocalName((elemParent = DOMUtil
2439: .getParent(collidingElem)))
2440: .equals(SchemaSymbols.ELT_REDEFINE))) {
2441: redefinedSchema = (XSDocumentInfo) (fRedefine2XSDMap
2442: .get(elemParent));
2443: // case where we're a redefining element.
2444: } else if ((DOMUtil.getLocalName(DOMUtil
2445: .getParent(currComp))
2446: .equals(SchemaSymbols.ELT_REDEFINE))) {
2447: redefinedSchema = collidingElemSchema;
2448: collidedWithRedefine = false;
2449: }
2450: if (redefinedSchema != null) { //redefinition involved somehow
2451: // If both components belong to the same document then
2452: // report an error and return.
2453: if (collidingElemSchema == currSchema) {
2454: reportSchemaError("sch-props-correct.2",
2455: new Object[] { qName }, currComp);
2456: return;
2457: }
2458:
2459: String newName = qName
2460: .substring(qName.lastIndexOf(',') + 1)
2461: + REDEF_IDENTIFIER;
2462: if (redefinedSchema == currSchema) { // object comp. okay here
2463: // now have to do some renaming...
2464: currComp.setAttribute(SchemaSymbols.ATT_NAME,
2465: newName);
2466: if (currSchema.fTargetNamespace == null) {
2467: registry.put("," + newName, currComp);
2468: registry_sub.put("," + newName, currSchema);
2469: } else {
2470: registry.put(currSchema.fTargetNamespace + ","
2471: + newName, currComp);
2472: registry_sub.put(currSchema.fTargetNamespace
2473: + "," + newName, currSchema);
2474: }
2475: // and take care of nested redefines by calling recursively:
2476: if (currSchema.fTargetNamespace == null)
2477: checkForDuplicateNames("," + newName, registry,
2478: registry_sub, currComp, currSchema);
2479: else
2480: checkForDuplicateNames(
2481: currSchema.fTargetNamespace + ","
2482: + newName, registry,
2483: registry_sub, currComp, currSchema);
2484: } else { // we may be redefining the wrong schema
2485: if (collidedWithRedefine) {
2486: if (currSchema.fTargetNamespace == null)
2487: checkForDuplicateNames("," + newName,
2488: registry, registry_sub, currComp,
2489: currSchema);
2490: else
2491: checkForDuplicateNames(
2492: currSchema.fTargetNamespace + ","
2493: + newName, registry,
2494: registry_sub, currComp, currSchema);
2495: } else {
2496: // error that redefined element in wrong schema
2497: reportSchemaError("sch-props-correct.2",
2498: new Object[] { qName }, currComp);
2499: }
2500: }
2501: } else {
2502: // we've just got a flat-out collision
2503: reportSchemaError("sch-props-correct.2",
2504: new Object[] { qName }, currComp);
2505: }
2506: }
2507: } // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void
2508:
2509: // the purpose of this method is to take the component of the
2510: // specified type and rename references to itself so that they
2511: // refer to the object being redefined. It takes special care of
2512: // <group>s and <attributeGroup>s to ensure that information
2513: // relating to implicit restrictions is preserved for those
2514: // traversers.
2515: private void renameRedefiningComponents(XSDocumentInfo currSchema,
2516: Element child, String componentType, String oldName,
2517: String newName) {
2518: if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
2519: Element grandKid = DOMUtil.getFirstChildElement(child);
2520: if (grandKid == null) {
2521: reportSchemaError("src-redefine.5.a.a", null, child);
2522: } else {
2523: String grandKidName = DOMUtil.getLocalName(grandKid);
2524: if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
2525: grandKid = DOMUtil.getNextSiblingElement(grandKid);
2526: }
2527: if (grandKid == null) {
2528: reportSchemaError("src-redefine.5.a.a", null, child);
2529: } else {
2530: grandKidName = DOMUtil.getLocalName(grandKid);
2531: if (!grandKidName
2532: .equals(SchemaSymbols.ELT_RESTRICTION)) {
2533: reportSchemaError("src-redefine.5.a.b",
2534: new Object[] { grandKidName }, child);
2535: } else {
2536: Object[] attrs = fAttributeChecker
2537: .checkAttributes(grandKid, false,
2538: currSchema);
2539: QName derivedBase = (QName) attrs[XSAttributeChecker.ATTIDX_BASE];
2540: if (derivedBase == null
2541: || derivedBase.uri != currSchema.fTargetNamespace
2542: || !derivedBase.localpart
2543: .equals(oldName)) {
2544: reportSchemaError(
2545: "src-redefine.5.a.c",
2546: new Object[] {
2547: grandKidName,
2548: (currSchema.fTargetNamespace == null ? ""
2549: : currSchema.fTargetNamespace)
2550: + "," + oldName },
2551: child);
2552: } else {
2553: // now we have to do the renaming...
2554: if (derivedBase.prefix != null
2555: && derivedBase.prefix.length() > 0)
2556: grandKid.setAttribute(
2557: SchemaSymbols.ATT_BASE,
2558: derivedBase.prefix + ":"
2559: + newName);
2560: else
2561: grandKid
2562: .setAttribute(
2563: SchemaSymbols.ATT_BASE,
2564: newName);
2565: // return true;
2566: }
2567: fAttributeChecker.returnAttrArray(attrs,
2568: currSchema);
2569: }
2570: }
2571: }
2572: } else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
2573: Element grandKid = DOMUtil.getFirstChildElement(child);
2574: if (grandKid == null) {
2575: reportSchemaError("src-redefine.5.b.a", null, child);
2576: } else {
2577: if (DOMUtil.getLocalName(grandKid).equals(
2578: SchemaSymbols.ELT_ANNOTATION)) {
2579: grandKid = DOMUtil.getNextSiblingElement(grandKid);
2580: }
2581: if (grandKid == null) {
2582: reportSchemaError("src-redefine.5.b.a", null, child);
2583: } else {
2584: // have to go one more level down; let another pass worry whether complexType is valid.
2585: Element greatGrandKid = DOMUtil
2586: .getFirstChildElement(grandKid);
2587: if (greatGrandKid == null) {
2588: reportSchemaError("src-redefine.5.b.b", null,
2589: grandKid);
2590: } else {
2591: String greatGrandKidName = DOMUtil
2592: .getLocalName(greatGrandKid);
2593: if (greatGrandKidName
2594: .equals(SchemaSymbols.ELT_ANNOTATION)) {
2595: greatGrandKid = DOMUtil
2596: .getNextSiblingElement(greatGrandKid);
2597: }
2598: if (greatGrandKid == null) {
2599: reportSchemaError("src-redefine.5.b.b",
2600: null, grandKid);
2601: } else {
2602: greatGrandKidName = DOMUtil
2603: .getLocalName(greatGrandKid);
2604: if (!greatGrandKidName
2605: .equals(SchemaSymbols.ELT_RESTRICTION)
2606: && !greatGrandKidName
2607: .equals(SchemaSymbols.ELT_EXTENSION)) {
2608: reportSchemaError(
2609: "src-redefine.5.b.c",
2610: new Object[] { greatGrandKidName },
2611: greatGrandKid);
2612: } else {
2613: Object[] attrs = fAttributeChecker
2614: .checkAttributes(greatGrandKid,
2615: false, currSchema);
2616: QName derivedBase = (QName) attrs[XSAttributeChecker.ATTIDX_BASE];
2617: if (derivedBase == null
2618: || derivedBase.uri != currSchema.fTargetNamespace
2619: || !derivedBase.localpart
2620: .equals(oldName)) {
2621: reportSchemaError(
2622: "src-redefine.5.b.d",
2623: new Object[] {
2624: greatGrandKidName,
2625: (currSchema.fTargetNamespace == null ? ""
2626: : currSchema.fTargetNamespace)
2627: + ","
2628: + oldName },
2629: greatGrandKid);
2630: } else {
2631: // now we have to do the renaming...
2632: if (derivedBase.prefix != null
2633: && derivedBase.prefix
2634: .length() > 0)
2635: greatGrandKid
2636: .setAttribute(
2637: SchemaSymbols.ATT_BASE,
2638: derivedBase.prefix
2639: + ":"
2640: + newName);
2641: else
2642: greatGrandKid.setAttribute(
2643: SchemaSymbols.ATT_BASE,
2644: newName);
2645: // return true;
2646: }
2647: }
2648: }
2649: }
2650: }
2651: }
2652: } else if (componentType
2653: .equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
2654: String processedBaseName = (currSchema.fTargetNamespace == null) ? ","
2655: + oldName
2656: : currSchema.fTargetNamespace + "," + oldName;
2657: int attGroupRefsCount = changeRedefineGroup(
2658: processedBaseName, componentType, newName, child,
2659: currSchema);
2660: if (attGroupRefsCount > 1) {
2661: reportSchemaError(
2662: "src-redefine.7.1",
2663: new Object[] { new Integer(attGroupRefsCount) },
2664: child);
2665: } else if (attGroupRefsCount == 1) {
2666: // return true;
2667: } else if (currSchema.fTargetNamespace == null)
2668: fRedefinedRestrictedAttributeGroupRegistry.put(
2669: processedBaseName, "," + newName);
2670: else
2671: fRedefinedRestrictedAttributeGroupRegistry.put(
2672: processedBaseName, currSchema.fTargetNamespace
2673: + "," + newName);
2674: } else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
2675: String processedBaseName = (currSchema.fTargetNamespace == null) ? ","
2676: + oldName
2677: : currSchema.fTargetNamespace + "," + oldName;
2678: int groupRefsCount = changeRedefineGroup(processedBaseName,
2679: componentType, newName, child, currSchema);
2680: if (groupRefsCount > 1) {
2681: reportSchemaError("src-redefine.6.1.1",
2682: new Object[] { new Integer(groupRefsCount) },
2683: child);
2684: } else if (groupRefsCount == 1) {
2685: // return true;
2686: } else {
2687: if (currSchema.fTargetNamespace == null)
2688: fRedefinedRestrictedGroupRegistry.put(
2689: processedBaseName, "," + newName);
2690: else
2691: fRedefinedRestrictedGroupRegistry
2692: .put(processedBaseName,
2693: currSchema.fTargetNamespace + ","
2694: + newName);
2695: }
2696: } else {
2697: reportSchemaError(
2698: "Internal-Error",
2699: new Object[] { "could not handle this particular <redefine>; please submit your schemas and instance document in a bug report!" },
2700: child);
2701: }
2702: // if we get here then we must have reported an error and failed somewhere...
2703: // return false;
2704: } // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void
2705:
2706: // this method takes a name of the form a:b, determines the URI mapped
2707: // to by a in the current SchemaNamespaceSupport object, and returns this
2708: // information in the form (nsURI,b) suitable for lookups in the global
2709: // decl Hashtables.
2710: // REVISIT: should have it return QName, instead of String. this would
2711: // save lots of string concatenation time. we can use
2712: // QName#equals() to compare two QNames, and use QName directly
2713: // as a key to the SymbolHash.
2714: // And when the DV's are ready to return compiled values from
2715: // validate() method, we should just call QNameDV.validate()
2716: // in this method.
2717: private String findQName(String name, XSDocumentInfo schemaDoc) {
2718: SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport;
2719: int colonPtr = name.indexOf(':');
2720: String prefix = XMLSymbols.EMPTY_STRING;
2721: if (colonPtr > 0)
2722: prefix = name.substring(0, colonPtr);
2723: String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix));
2724: String localpart = (colonPtr == 0) ? name : name
2725: .substring(colonPtr + 1);
2726: if (prefix == XMLSymbols.EMPTY_STRING && uri == null
2727: && schemaDoc.fIsChameleonSchema)
2728: uri = schemaDoc.fTargetNamespace;
2729: if (uri == null)
2730: return "," + localpart;
2731: return uri + "," + localpart;
2732: } // findQName(String, XSDocumentInfo): String
2733:
2734: // This function looks among the children of curr for an element of type elementSought.
2735: // If it finds one, it evaluates whether its ref attribute contains a reference
2736: // to originalQName. If it does, it returns 1 + the value returned by
2737: // calls to itself on all other children. In all other cases it returns 0 plus
2738: // the sum of the values returned by calls to itself on curr's children.
2739: // It also resets the value of ref so that it will refer to the renamed type from the schema
2740: // being redefined.
2741: private int changeRedefineGroup(String originalQName,
2742: String elementSought, String newName, Element curr,
2743: XSDocumentInfo schemaDoc) {
2744: int result = 0;
2745: for (Element child = DOMUtil.getFirstChildElement(curr); child != null; child = DOMUtil
2746: .getNextSiblingElement(child)) {
2747: String name = DOMUtil.getLocalName(child);
2748: if (!name.equals(elementSought))
2749: result += changeRedefineGroup(originalQName,
2750: elementSought, newName, child, schemaDoc);
2751: else {
2752: String ref = child.getAttribute(SchemaSymbols.ATT_REF);
2753: if (ref.length() != 0) {
2754: String processedRef = findQName(ref, schemaDoc);
2755: if (originalQName.equals(processedRef)) {
2756: String prefix = XMLSymbols.EMPTY_STRING;
2757: int colonptr = ref.indexOf(":");
2758: if (colonptr > 0) {
2759: prefix = ref.substring(0, colonptr);
2760: child.setAttribute(SchemaSymbols.ATT_REF,
2761: prefix + ":" + newName);
2762: } else
2763: child.setAttribute(SchemaSymbols.ATT_REF,
2764: newName);
2765: result++;
2766: if (elementSought
2767: .equals(SchemaSymbols.ELT_GROUP)) {
2768: String minOccurs = child
2769: .getAttribute(SchemaSymbols.ATT_MINOCCURS);
2770: String maxOccurs = child
2771: .getAttribute(SchemaSymbols.ATT_MAXOCCURS);
2772: if (!((maxOccurs.length() == 0 || maxOccurs
2773: .equals("1")) && (minOccurs
2774: .length() == 0 || minOccurs
2775: .equals("1")))) {
2776: reportSchemaError("src-redefine.6.1.2",
2777: new Object[] { ref }, child);
2778: }
2779: }
2780: }
2781: } // if ref was null some other stage of processing will flag the error
2782: }
2783: }
2784: return result;
2785: } // changeRedefineGroup
2786:
2787: // this method returns the XSDocumentInfo object that contains the
2788: // component corresponding to decl. If components from this
2789: // document cannot be referred to from those of currSchema, this
2790: // method returns null; it's up to the caller to throw an error.
2791: // @param: currSchema: the XSDocumentInfo object containing the
2792: // decl ref'ing us.
2793: // @param: decl: the declaration being ref'd.
2794: // this method is superficial now. ---Jack
2795: private XSDocumentInfo findXSDocumentForDecl(
2796: XSDocumentInfo currSchema, Element decl,
2797: XSDocumentInfo decl_Doc) {
2798:
2799: if (DEBUG_NODE_POOL) {
2800: System.out.println("DOCUMENT NS:"
2801: + currSchema.fTargetNamespace + " hashcode:"
2802: + ((Object) currSchema.fSchemaElement).hashCode());
2803: }
2804: Object temp = decl_Doc;
2805: if (temp == null) {
2806: // something went badly wrong; we don't know this doc?
2807: return null;
2808: }
2809: XSDocumentInfo declDocInfo = (XSDocumentInfo) temp;
2810: return declDocInfo;
2811: /*********
2812: Logic here is unnecessary after schema WG's recent decision to allow
2813: schema components from one document to refer to components of any other,
2814: so long as there's some include/import/redefine path amongst them.
2815: If they rver reverse this decision the code's right here though... - neilg
2816: // now look in fDependencyMap to see if this is reachable
2817: if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
2818: return declDocInfo;
2819: }
2820: // obviously the requesting doc didn't include, redefine or
2821: // import the one containing decl...
2822: return null;
2823: **********/
2824: } // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo
2825:
2826: // returns whether more than <annotation>s occur in children of elem
2827: private boolean nonAnnotationContent(Element elem) {
2828: for (Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil
2829: .getNextSiblingElement(child)) {
2830: if (!(DOMUtil.getLocalName(child)
2831: .equals(SchemaSymbols.ELT_ANNOTATION)))
2832: return true;
2833: }
2834: return false;
2835: } // nonAnnotationContent(Element): boolean
2836:
2837: private void setSchemasVisible(XSDocumentInfo startSchema) {
2838: if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) {
2839: // make it visible
2840: DOMUtil
2841: .setVisible(startSchema.fSchemaElement,
2842: fHiddenNodes);
2843: Vector dependingSchemas = (Vector) fDependencyMap
2844: .get(startSchema);
2845: for (int i = 0; i < dependingSchemas.size(); i++) {
2846: setSchemasVisible((XSDocumentInfo) dependingSchemas
2847: .elementAt(i));
2848: }
2849: }
2850: // if it's visible already than so must be its children
2851: } // setSchemasVisible(XSDocumentInfo): void
2852:
2853: private SimpleLocator xl = new SimpleLocator();
2854:
2855: /**
2856: * Extract location information from an Element node, and create a
2857: * new SimpleLocator object from such information. Returning null means
2858: * no information can be retrieved from the element.
2859: */
2860: public SimpleLocator element2Locator(Element e) {
2861: if (!(e instanceof ElementImpl))
2862: return null;
2863:
2864: SimpleLocator l = new SimpleLocator();
2865: return element2Locator(e, l) ? l : null;
2866: }
2867:
2868: /**
2869: * Extract location information from an Element node, store such
2870: * information in the passed-in SimpleLocator object, then return
2871: * true. Returning false means can't extract or store such information.
2872: */
2873: public boolean element2Locator(Element e, SimpleLocator l) {
2874: if (l == null)
2875: return false;
2876: if (e instanceof ElementImpl) {
2877: ElementImpl ele = (ElementImpl) e;
2878: // get system id from document object
2879: Document doc = ele.getOwnerDocument();
2880: String sid = (String) fDoc2SystemId.get(DOMUtil
2881: .getRoot(doc));
2882: // line/column numbers are stored in the element node
2883: int line = ele.getLineNumber();
2884: int column = ele.getColumnNumber();
2885: l.setValues(sid, sid, line, column, ele
2886: .getCharacterOffset());
2887: return true;
2888: }
2889: return false;
2890: }
2891:
2892: void reportSchemaError(String key, Object[] args, Element ele) {
2893: if (element2Locator(ele, xl)) {
2894: fErrorReporter.reportError(xl,
2895: XSMessageFormatter.SCHEMA_DOMAIN, key, args,
2896: XMLErrorReporter.SEVERITY_ERROR);
2897: } else {
2898: fErrorReporter.reportError(
2899: XSMessageFormatter.SCHEMA_DOMAIN, key, args,
2900: XMLErrorReporter.SEVERITY_ERROR);
2901: }
2902: }
2903:
2904: void reportSchemaWarning(String key, Object[] args, Element ele) {
2905: if (element2Locator(ele, xl)) {
2906: fErrorReporter.reportError(xl,
2907: XSMessageFormatter.SCHEMA_DOMAIN, key, args,
2908: XMLErrorReporter.SEVERITY_WARNING);
2909: } else {
2910: fErrorReporter.reportError(
2911: XSMessageFormatter.SCHEMA_DOMAIN, key, args,
2912: XMLErrorReporter.SEVERITY_WARNING);
2913: }
2914: }
2915:
2916: /**
2917: * Grammar pool used for validating annotations. This will return all of the
2918: * grammars from the grammar bucket. It will also return an object for the
2919: * schema for schemas which will contain at least the relevant declarations
2920: * for annotations.
2921: */
2922: private static class XSAnnotationGrammarPool implements
2923: XMLGrammarPool {
2924:
2925: private XSGrammarBucket fGrammarBucket;
2926: private Grammar[] fInitialGrammarSet;
2927:
2928: public Grammar[] retrieveInitialGrammarSet(String grammarType) {
2929: if (grammarType == XMLGrammarDescription.XML_SCHEMA) {
2930: if (fInitialGrammarSet == null) {
2931: if (fGrammarBucket == null) {
2932: fInitialGrammarSet = new Grammar[] { SchemaGrammar.SG_Schema4Annotations };
2933: } else {
2934: SchemaGrammar[] schemaGrammars = fGrammarBucket
2935: .getGrammars();
2936: /**
2937: * If the grammar bucket already contains the schema for schemas
2938: * then we already have the definitions for the parts relevant
2939: * to annotations.
2940: */
2941: for (int i = 0; i < schemaGrammars.length; ++i) {
2942: if (SchemaSymbols.URI_SCHEMAFORSCHEMA
2943: .equals(schemaGrammars[i]
2944: .getTargetNamespace())) {
2945: fInitialGrammarSet = schemaGrammars;
2946: return fInitialGrammarSet;
2947: }
2948: }
2949: Grammar[] grammars = new Grammar[schemaGrammars.length + 1];
2950: System.arraycopy(schemaGrammars, 0, grammars,
2951: 0, schemaGrammars.length);
2952: grammars[grammars.length - 1] = SchemaGrammar.SG_Schema4Annotations;
2953: fInitialGrammarSet = grammars;
2954: }
2955: }
2956: return fInitialGrammarSet;
2957: }
2958: return new Grammar[0];
2959: }
2960:
2961: public void cacheGrammars(String grammarType, Grammar[] grammars) {
2962:
2963: }
2964:
2965: public Grammar retrieveGrammar(XMLGrammarDescription desc) {
2966: if (desc.getGrammarType() == XMLGrammarDescription.XML_SCHEMA) {
2967: final String tns = ((XMLSchemaDescription) desc)
2968: .getTargetNamespace();
2969: if (fGrammarBucket != null) {
2970: Grammar grammar = fGrammarBucket.getGrammar(tns);
2971: if (grammar != null) {
2972: return grammar;
2973: }
2974: }
2975: if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(tns)) {
2976: return SchemaGrammar.SG_Schema4Annotations;
2977: }
2978: }
2979: return null;
2980: }
2981:
2982: public void refreshGrammars(XSGrammarBucket gBucket) {
2983: fGrammarBucket = gBucket;
2984: fInitialGrammarSet = null;
2985: }
2986:
2987: public void lockPool() {
2988: }
2989:
2990: public void unlockPool() {
2991: }
2992:
2993: public void clear() {
2994: }
2995: }
2996:
2997: /**
2998: * used to identify a reference to a schema document
2999: * if the same document is referenced twice with the same key, then
3000: * we only need to parse it once.
3001: *
3002: * When 2 XSDKey's are compared, the following table can be used to
3003: * determine whether they are equal:
3004: * inc red imp pre ins
3005: * inc N/L ? N/L N/L N/L
3006: * red ? N/L ? ? ?
3007: * imp N/L ? N/P N/P N/P
3008: * pre N/L ? N/P N/P N/P
3009: * ins N/L ? N/P N/P N/P
3010: *
3011: * Where: N/L: duplicate when they have the same namespace and location.
3012: * ? : not clear from the spec.
3013: * REVISIT: to simplify the process, also considering
3014: * it's very rare, we treat them as not duplicate.
3015: * N/P: not possible. imp/pre/ins are referenced by namespace.
3016: * when the first time we encounter a schema document for a
3017: * namespace, we create a grammar and store it in the grammar
3018: * bucket. when we see another reference to the same namespace,
3019: * we first check whether a grammar with the same namespace is
3020: * already in the bucket, which is true in this case, so we
3021: * won't create another XSDKey.
3022: *
3023: * Conclusion from the table: two XSDKey's are duplicate only when all of
3024: * the following are true:
3025: * 1. They are both "redefine", or neither is "redefine";
3026: * 2. They have the same namespace;
3027: * 3. They have the same non-null location.
3028: *
3029: * About 3: if neither has a non-null location, then it's the case where
3030: * 2 input streams are provided, but no system ID is provided. We can't tell
3031: * whether the 2 streams have the same content, so we treat them as not
3032: * duplicate.
3033: */
3034: private static class XSDKey {
3035: String systemId;
3036: short referType;
3037: // for inclue/redefine, this is the enclosing namespace
3038: // for import/preparse/instance, this is the target namespace
3039: String referNS;
3040:
3041: XSDKey(String systemId, short referType, String referNS) {
3042: this .systemId = systemId;
3043: this .referType = referType;
3044: this .referNS = referNS;
3045: }
3046:
3047: public int hashCode() {
3048: // according to the description at the beginning of this class,
3049: // we use the hashcode of the namespace as the hashcoe of this key.
3050: return referNS == null ? 0 : referNS.hashCode();
3051: }
3052:
3053: public boolean equals(Object obj) {
3054: if (!(obj instanceof XSDKey)) {
3055: return false;
3056: }
3057: XSDKey key = (XSDKey) obj;
3058:
3059: // condition 1: both are redefine
3060: /** if (referType == XSDDescription.CONTEXT_REDEFINE ||
3061: key.referType == XSDDescription.CONTEXT_REDEFINE) {
3062: if (referType != key.referType)
3063: return false;
3064: }**/
3065:
3066: // condition 2: same namespace
3067: if (referNS != key.referNS)
3068: return false;
3069:
3070: // condition 3: same non-null location
3071: if (systemId == null || !systemId.equals(key.systemId)) {
3072: return false;
3073: }
3074:
3075: return true;
3076: }
3077: }
3078:
3079: /**
3080: * @param state
3081: */
3082: public void setGenerateSyntheticAnnotations(boolean state) {
3083: fSchemaParser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS, state);
3084: }
3085:
3086: } // XSDHandler
|