1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2004 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xerces" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.impl.xs.traversers;
  58. import java.io.IOException;
  59. import java.util.Hashtable;
  60. import java.util.Stack;
  61. import java.util.Vector;
  62. import javax.xml.transform.Source;
  63. import javax.xml.transform.Transformer;
  64. import javax.xml.transform.TransformerException;
  65. import javax.xml.transform.TransformerFactory;
  66. import javax.xml.transform.dom.DOMSource;
  67. import javax.xml.transform.sax.SAXSource;
  68. import javax.xml.transform.sax.SAXResult;
  69. import javax.xml.transform.stream.StreamSource;
  70. import com.sun.org.apache.xerces.internal.impl.Constants;
  71. import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  72. import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  73. import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
  74. import com.sun.org.apache.xerces.internal.impl.xs.SchemaNamespaceSupport;
  75. import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  76. import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaException;
  77. import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader;
  78. import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
  79. import com.sun.org.apache.xerces.internal.impl.xs.XSDDescription;
  80. import com.sun.org.apache.xerces.internal.impl.xs.XSDeclarationPool;
  81. import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
  82. import com.sun.org.apache.xerces.internal.impl.xs.XSGrammarBucket;
  83. import com.sun.org.apache.xerces.internal.impl.xs.XSGroupDecl;
  84. import com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter;
  85. import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl;
  86. import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
  87. import com.sun.org.apache.xerces.internal.impl.xs.opti.ElementImpl;
  88. import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM;
  89. import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser;
  90. import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaParsingConfig;
  91. import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator;
  92. import com.sun.org.apache.xerces.internal.parsers.SAXParser;
  93. import com.sun.org.apache.xerces.internal.util.DOMUtil;
  94. import com.sun.org.apache.xerces.internal.util.SecurityManager;
  95. import com.sun.org.apache.xerces.internal.util.SAX2XNI;
  96. import com.sun.org.apache.xerces.internal.util.SymbolTable;
  97. import com.sun.org.apache.xerces.internal.util.XMLInputSourceAdaptor;
  98. import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  99. import com.sun.org.apache.xerces.internal.xni.QName;
  100. import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  101. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  102. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  103. import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  104. import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
  105. import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  106. import com.sun.org.apache.xerces.internal.xs.XSObject;
  107. import org.w3c.dom.Document;
  108. import org.w3c.dom.Element;
  109. import org.w3c.dom.Node;
  110. import org.xml.sax.XMLReader;
  111. import org.xml.sax.SAXException;
  112. /**
  113. * The purpose of this class is to co-ordinate the construction of a
  114. * grammar object corresponding to a schema. To do this, it must be
  115. * prepared to parse several schema documents (for instance if the
  116. * schema document originally referred to contains <include> or
  117. * <redefined> information items). If any of the schemas imports a
  118. * schema, other grammars may be constructed as a side-effect.
  119. *
  120. * @author Neil Graham, IBM
  121. * @author Pavani Mukthipudi, Sun Microsystems
  122. * @version $Id: XSDHandler.java,v 1.75 2004/02/03 17:27:45 sandygao Exp $
  123. */
  124. public class XSDHandler {
  125. /** Feature identifier: allow java encodings */
  126. protected static final String ALLOW_JAVA_ENCODINGS =
  127. Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
  128. /** Feature identifier: continue after fatal error */
  129. protected static final String CONTINUE_AFTER_FATAL_ERROR =
  130. Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
  131. /** Feature identifier: allow java encodings */
  132. protected static final String STANDARD_URI_CONFORMANT_FEATURE =
  133. Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
  134. /** Feature: disallow doctype*/
  135. protected static final String DISALLOW_DOCTYPE =
  136. Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
  137. /** Property identifier: error handler. */
  138. protected static final String ERROR_HANDLER =
  139. Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
  140. /** Property identifier: JAXP schema source. */
  141. protected static final String JAXP_SCHEMA_SOURCE =
  142. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
  143. /** Property identifier: entity resolver. */
  144. public static final String ENTITY_RESOLVER =
  145. Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  146. private static final String SECURE_PROCESSING =
  147. Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  148. /** Property identifier: entity manager. */
  149. protected static final String ENTITY_MANAGER =
  150. Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
  151. /** Property identifier: error reporter. */
  152. public static final String ERROR_REPORTER =
  153. Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  154. /** Property identifier: grammar pool. */
  155. public static final String XMLGRAMMAR_POOL =
  156. Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
  157. /** Property identifier: symbol table. */
  158. public static final String SYMBOL_TABLE =
  159. Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  160. protected static final String SECURITY_MANAGER =
  161. Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  162. /**
  163. * Property identifier: security manager.
  164. */
  165. protected static final boolean DEBUG_NODE_POOL = false;
  166. // Data
  167. // different sorts of declarations; should make lookup and
  168. // traverser calling more efficient/less bulky.
  169. final static int ATTRIBUTE_TYPE = 1;
  170. final static int ATTRIBUTEGROUP_TYPE = 2;
  171. final static int ELEMENT_TYPE = 3;
  172. final static int GROUP_TYPE = 4;
  173. final static int IDENTITYCONSTRAINT_TYPE = 5;
  174. final static int NOTATION_TYPE = 6;
  175. final static int TYPEDECL_TYPE = 7;
  176. // this string gets appended to redefined names; it's purpose is to be
  177. // as unlikely as possible to cause collisions.
  178. public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
  179. //
  180. //protected data that can be accessable by any traverser
  181. // stores <notation> decl
  182. protected Hashtable fNotationRegistry = new Hashtable();
  183. protected XSDeclarationPool fDeclPool = null;
  184. // are java encodings allowed?
  185. private boolean fAllowJavaEncodings = false;
  186. // enforcing strict uri?
  187. private boolean fStrictURI = false;
  188. /**
  189. * <p>Security manager in effect.</p>
  190. *
  191. * <p>Protected to allow access by any traverser.</p>
  192. */
  193. protected SecurityManager fSecureProcessing = null;
  194. // These tables correspond to the symbol spaces defined in the
  195. // spec.
  196. // They are keyed with a QName (that is, String("URI,localpart) and
  197. // their values are nodes corresponding to the given name's decl.
  198. // By asking the node for its ownerDocument and looking in
  199. // XSDocumentInfoRegistry we can easily get the corresponding
  200. // XSDocumentInfo object.
  201. private Hashtable fUnparsedAttributeRegistry = new Hashtable();
  202. private Hashtable fUnparsedAttributeGroupRegistry = new Hashtable();
  203. private Hashtable fUnparsedElementRegistry = new Hashtable();
  204. private Hashtable fUnparsedGroupRegistry = new Hashtable();
  205. private Hashtable fUnparsedIdentityConstraintRegistry = new Hashtable();
  206. private Hashtable fUnparsedNotationRegistry = new Hashtable();
  207. private Hashtable fUnparsedTypeRegistry = new Hashtable();
  208. // this is keyed with a documentNode (or the schemaRoot nodes
  209. // contained in the XSDocumentInfo objects) and its value is the
  210. // XSDocumentInfo object corresponding to that document.
  211. // Basically, the function of this registry is to be a link
  212. // between the nodes we fetch from calls to the fUnparsed*
  213. // arrays and the XSDocumentInfos they live in.
  214. private Hashtable fXSDocumentInfoRegistry = new Hashtable();
  215. // this hashtable is keyed on by XSDocumentInfo objects. Its values
  216. // are Vectors containing the XSDocumentInfo objects <include>d,
  217. // <import>ed or <redefine>d by the key XSDocumentInfo.
  218. private Hashtable fDependencyMap = new Hashtable();
  219. // this hashtable is keyed on by a target namespace. Its values
  220. // are Vectors containing namespaces imported by schema documents
  221. // with the key target namespace.
  222. // if an imprted schema has absent namespace, the value "null" is stored.
  223. private Hashtable fImportMap = new Hashtable();
  224. // all namespaces that imports other namespaces
  225. // if the importing schema has absent namespace, empty string is stored.
  226. // (because the key of a hashtable can't be null.)
  227. private Vector fAllTNSs = new Vector();
  228. // stores instance document mappings between namespaces and schema hints
  229. private Hashtable fLocationPairs = null;
  230. // convenience methods
  231. private String null2EmptyString(String ns) {
  232. return ns == null ? XMLSymbols.EMPTY_STRING : ns;
  233. }
  234. private String emptyString2Null(String ns) {
  235. return ns == XMLSymbols.EMPTY_STRING ? null : ns;
  236. }
  237. // This vector stores strings which are combinations of the
  238. // publicId and systemId of the inputSource corresponding to a
  239. // schema document. This combination is used so that the user's
  240. // EntityResolver can provide a consistent way of identifying a
  241. // schema document that is included in multiple other schemas.
  242. private Hashtable fTraversed = new Hashtable();
  243. // this hashtable contains a mapping from Document to its systemId
  244. // this is useful to resolve a uri relative to the referring document
  245. private Hashtable fDoc2SystemId = new Hashtable();
  246. // the primary XSDocumentInfo we were called to parse
  247. private XSDocumentInfo fRoot = null;
  248. // This hashtable's job is to act as a link between the document
  249. // node at the root of the parsed schema's tree and its
  250. // XSDocumentInfo object.
  251. private Hashtable fDoc2XSDocumentMap = new Hashtable();
  252. // map between <redefine> elements and the XSDocumentInfo
  253. // objects that correspond to the documents being redefined.
  254. private Hashtable fRedefine2XSDMap = new Hashtable();
  255. // map between <redefine> elements and the namespace support
  256. private Hashtable fRedefine2NSSupport = new Hashtable();
  257. // these objects store a mapping between the names of redefining
  258. // groups/attributeGroups and the groups/AttributeGroups which
  259. // they redefine by restriction (implicitly). It is up to the
  260. // Group and AttributeGroup traversers to check these restrictions for
  261. // validity.
  262. private Hashtable fRedefinedRestrictedAttributeGroupRegistry = new Hashtable();
  263. private Hashtable fRedefinedRestrictedGroupRegistry = new Hashtable();
  264. // a variable storing whether the last schema document
  265. // processed (by getSchema) was a duplicate.
  266. private boolean fLastSchemaWasDuplicate;
  267. // the XMLErrorReporter
  268. private XMLErrorReporter fErrorReporter;
  269. private XMLEntityResolver fEntityResolver;
  270. // the XSAttributeChecker
  271. private XSAttributeChecker fAttributeChecker;
  272. // the symbol table
  273. private SymbolTable fSymbolTable;
  274. // the GrammarResolver
  275. private XSGrammarBucket fGrammarBucket;
  276. // the Grammar description
  277. private XSDDescription fSchemaGrammarDescription;
  278. // the Grammar Pool
  279. private XMLGrammarPool fGrammarPool;
  280. //************ Traversers **********
  281. XSDAttributeGroupTraverser fAttributeGroupTraverser;
  282. XSDAttributeTraverser fAttributeTraverser;
  283. XSDComplexTypeTraverser fComplexTypeTraverser;
  284. XSDElementTraverser fElementTraverser;
  285. XSDGroupTraverser fGroupTraverser;
  286. XSDKeyrefTraverser fKeyrefTraverser;
  287. XSDNotationTraverser fNotationTraverser;
  288. XSDSimpleTypeTraverser fSimpleTypeTraverser;
  289. XSDUniqueOrKeyTraverser fUniqueOrKeyTraverser;
  290. XSDWildcardTraverser fWildCardTraverser;
  291. //DOMParser fSchemaParser;
  292. SchemaParsingConfig fSchemaParser;
  293. // these data members are needed for the deferred traversal
  294. // of local elements.
  295. // the initial size of the array to store deferred local elements
  296. private static final int INIT_STACK_SIZE = 30;
  297. // the incremental size of the array to store deferred local elements
  298. private static final int INC_STACK_SIZE = 10;
  299. // current position of the array (# of deferred local elements)
  300. private int fLocalElemStackPos = 0;
  301. private XSParticleDecl[] fParticle = new XSParticleDecl[INIT_STACK_SIZE];
  302. private Element[] fLocalElementDecl = new Element[INIT_STACK_SIZE];
  303. private int[] fAllContext = new int[INIT_STACK_SIZE];
  304. private XSObject[] fParent = new XSObject[INIT_STACK_SIZE];
  305. private String [][] fLocalElemNamespaceContext = new String [INIT_STACK_SIZE][1];
  306. // these data members are needed for the deferred traversal
  307. // of keyrefs.
  308. // the initial size of the array to store deferred keyrefs
  309. private static final int INIT_KEYREF_STACK = 2;
  310. // the incremental size of the array to store deferred keyrefs
  311. private static final int INC_KEYREF_STACK_AMOUNT = 2;
  312. // current position of the array (# of deferred keyrefs)
  313. private int fKeyrefStackPos = 0;
  314. private Element [] fKeyrefs = new Element[INIT_KEYREF_STACK];
  315. private XSElementDecl [] fKeyrefElems = new XSElementDecl [INIT_KEYREF_STACK];
  316. private String [][] fKeyrefNamespaceContext = new String[INIT_KEYREF_STACK][1];
  317. // Constructors
  318. public XSDHandler(){
  319. fSchemaParser = new SchemaParsingConfig();
  320. }
  321. // it should be possible to use the same XSDHandler to parse
  322. // multiple schema documents; this will allow one to be
  323. // constructed.
  324. public XSDHandler (XSGrammarBucket gBucket) {
  325. this();
  326. fGrammarBucket = gBucket;
  327. // Note: don't use SchemaConfiguration internally
  328. // we will get stack overflaw because
  329. // XMLSchemaValidator will be instantiating XSDHandler...
  330. fSchemaGrammarDescription = new XSDDescription();
  331. } // end constructor
  332. /**
  333. * This method initiates the parse of a schema. It will likely be
  334. * called from the Validator and it will make the
  335. * resulting grammar available; it returns a reference to this object just
  336. * in case. A reset(XMLComponentManager) must be called before this methods is called.
  337. * @param is
  338. * @param desc
  339. * @param locationPairs
  340. * @return
  341. * @throws IOException
  342. */
  343. public SchemaGrammar parseSchema(Source source, XSDDescription desc,
  344. Hashtable locationPairs)
  345. throws IOException {
  346. fLocationPairs = locationPairs;
  347. if (fSchemaParser != null) {
  348. fSchemaParser.resetNodePool();
  349. }
  350. SchemaGrammar grammar = null;
  351. String schemaNamespace = null;
  352. short referType = desc.getContextType();
  353. // if loading using JAXP schemaSource property, or using grammar caching loadGrammar
  354. // the desc.targetNamespace is always null.
  355. // Therefore we should not attempt to find out if
  356. // the schema is already in the bucket, since in the case we have
  357. // no namespace schema in the bucket, findGrammar will always return the
  358. // no namespace schema.
  359. if (referType != XSDDescription.CONTEXT_PREPARSE){
  360. // first try to find it in the bucket/pool, return if one is found
  361. grammar = findGrammar(desc);
  362. if (grammar != null)
  363. return grammar;
  364. schemaNamespace = desc.getTargetNamespace();
  365. // handle empty string URI as null
  366. if (schemaNamespace != null) {
  367. schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
  368. }
  369. }
  370. // before parsing a schema, need to clear registries associated with
  371. // parsing schemas
  372. prepareForParse();
  373. // first phase: construct trees.
  374. Document schemaRoot = getSchema(schemaNamespace, source,
  375. referType == XSDDescription.CONTEXT_PREPARSE,
  376. referType, null);
  377. if (schemaRoot == null) {
  378. // something went wrong right off the hop
  379. return null;
  380. }
  381. if ( referType == XSDDescription.CONTEXT_PREPARSE) {
  382. Element schemaElem = DOMUtil.getRoot(schemaRoot);
  383. schemaNamespace = DOMUtil.getAttrValue(schemaElem, SchemaSymbols.ATT_TARGETNAMESPACE);
  384. if(schemaNamespace != null && schemaNamespace.length() > 0) {
  385. // Since now we've discovered a namespace, we need to update xsd key
  386. // and store this schema in traversed schemas bucket
  387. schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
  388. desc.setTargetNamespace(schemaNamespace);
  389. }
  390. else {
  391. schemaNamespace = null;
  392. }
  393. grammar = findGrammar(desc);
  394. if (grammar != null)
  395. return grammar;
  396. String schemaId = source.getSystemId();
  397. XSDKey key = new XSDKey(schemaId, referType, schemaNamespace);
  398. fTraversed.put(key, schemaRoot );
  399. if (schemaId != null) {
  400. fDoc2SystemId.put(schemaRoot, schemaId );
  401. }
  402. }
  403. // before constructing trees and traversing a schema, need to reset
  404. // all traversers and clear all registries
  405. prepareForTraverse();
  406. fRoot = constructTrees(schemaRoot, source.getSystemId(), desc);
  407. if (fRoot == null) {
  408. return null;
  409. }
  410. // second phase: fill global registries.
  411. buildGlobalNameRegistries();
  412. // third phase: call traversers
  413. traverseSchemas();
  414. // fourth phase: handle local element decls
  415. traverseLocalElements();
  416. // fifth phase: handle Keyrefs
  417. resolveKeyRefs();
  418. // sixth phase: validate attribute of non-schema namespaces
  419. // REVISIT: skip this for now. we really don't want to do it.
  420. //fAttributeChecker.checkNonSchemaAttributes(fGrammarBucket);
  421. // seventh phase: store imported grammars
  422. // for all grammars with <import>s
  423. for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
  424. // get its target namespace
  425. String tns = (String)fAllTNSs.elementAt(i);
  426. // get all namespaces it imports
  427. Vector ins = (Vector)fImportMap.get(tns);
  428. // get the grammar
  429. SchemaGrammar sg = fGrammarBucket.getGrammar(emptyString2Null(tns));
  430. if (sg == null)
  431. continue;
  432. SchemaGrammar isg;
  433. // for imported namespace
  434. int count = 0;
  435. for (int j = 0; j < ins.size(); j++) {
  436. // get imported grammar
  437. isg = fGrammarBucket.getGrammar((String)ins.elementAt(j));
  438. // reuse the same vector
  439. if (isg != null)
  440. ins.setElementAt(isg, count++);
  441. }
  442. ins.setSize(count);
  443. // set the imported grammars
  444. sg.setImportedGrammars(ins);
  445. }
  446. // and return.
  447. return fGrammarBucket.getGrammar(fRoot.fTargetNamespace);
  448. } // end parseSchema
  449. /**
  450. * Pull the grammar out of the bucket simply using
  451. * its TNS as a key
  452. */
  453. SchemaGrammar getGrammar(String tns) {
  454. return fGrammarBucket.getGrammar(tns);
  455. }
  456. /**
  457. * First try to find a grammar in the bucket, if failed, consult the
  458. * grammar pool. If a grammar is found in the pool, then add it (and all
  459. * imported ones) into the bucket.
  460. */
  461. protected SchemaGrammar findGrammar(XSDDescription desc) {
  462. SchemaGrammar sg = fGrammarBucket.getGrammar(desc.getTargetNamespace());
  463. if (sg == null) {
  464. if (fGrammarPool != null) {
  465. sg = (SchemaGrammar)fGrammarPool.retrieveGrammar(desc);
  466. if (sg != null) {
  467. // put this grammar into the bucket, along with grammars
  468. // imported by it (directly or indirectly)
  469. if (!fGrammarBucket.putGrammar(sg, true)) {
  470. // REVISIT: a conflict between new grammar(s) and grammars
  471. // in the bucket. What to do? A warning? An exception?
  472. reportSchemaWarning("GrammarConflict", null, null);
  473. sg = null;
  474. }
  475. }
  476. }
  477. }
  478. return sg;
  479. }
  480. // may wish to have setter methods for ErrorHandler,
  481. // EntityResolver...
  482. private static final String[][] NS_ERROR_CODES = {
  483. {"src-include.2.1", "src-include.2.1"},
  484. {"src-redefine.3.1", "src-redefine.3.1"},
  485. {"src-import.3.1", "src-import.3.2"},
  486. null,
  487. {"TargetNamespace.1", "TargetNamespace.2"},
  488. {"TargetNamespace.1", "TargetNamespace.2"},
  489. {"TargetNamespace.1", "TargetNamespace.2"},
  490. {"TargetNamespace.1", "TargetNamespace.2"}
  491. };
  492. private static final String[] ELE_ERROR_CODES = {
  493. "src-include.1", "src-redefine.2", "src-import.2", "schema_reference.4",
  494. "schema_reference.4", "schema_reference.4", "schema_reference.4", "schema_reference.4"
  495. };
  496. // This method does several things:
  497. // It constructs an instance of an XSDocumentInfo object using the
  498. // schemaRoot node. Then, for each <include>,
  499. // <redefine>, and <import> children, it attempts to resolve the
  500. // requested schema document, initiates a DOM parse, and calls
  501. // itself recursively on that document's root. It also records in
  502. // the DependencyMap object what XSDocumentInfo objects its XSDocumentInfo
  503. // depends on.
  504. // It also makes sure the targetNamespace of the schema it was
  505. // called to parse is correct.
  506. protected XSDocumentInfo constructTrees(Document schemaRoot, String locationHint, XSDDescription desc) {
  507. if (schemaRoot == null) return null;
  508. String callerTNS = desc.getTargetNamespace();
  509. short referType = desc.getContextType();
  510. XSDocumentInfo currSchemaInfo = null;
  511. try {
  512. // note that attributes are freed at end of traverseSchemas()
  513. currSchemaInfo = new XSDocumentInfo(schemaRoot, fAttributeChecker, fSymbolTable);
  514. } catch (XMLSchemaException se) {
  515. reportSchemaError(ELE_ERROR_CODES[referType],
  516. new Object[]{locationHint},
  517. DOMUtil.getRoot(schemaRoot));
  518. return null;
  519. }
  520. // targetNamespace="" is not valid, issue a warning, and ignore it
  521. if (currSchemaInfo.fTargetNamespace != null &&
  522. currSchemaInfo.fTargetNamespace.length() == 0) {
  523. reportSchemaWarning("EmptyTargetNamespace",
  524. new Object[]{locationHint},
  525. DOMUtil.getRoot(schemaRoot));
  526. currSchemaInfo.fTargetNamespace = null;
  527. }
  528. if (callerTNS != null) {
  529. // the second index to the NS_ERROR_CODES array
  530. // if the caller/expected NS is not absent, we use the first column
  531. int secondIdx = 0;
  532. // for include and redefine
  533. if (referType == XSDDescription.CONTEXT_INCLUDE ||
  534. referType == XSDDescription.CONTEXT_REDEFINE) {
  535. // if the referred document has no targetNamespace,
  536. // it's a chameleon schema
  537. if (currSchemaInfo.fTargetNamespace == null) {
  538. currSchemaInfo.fTargetNamespace = callerTNS;
  539. currSchemaInfo.fIsChameleonSchema = true;
  540. }
  541. // if the referred document has a target namespace differing
  542. // from the caller, it's an error
  543. else if (callerTNS != currSchemaInfo.fTargetNamespace) {
  544. reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
  545. new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
  546. DOMUtil.getRoot(schemaRoot));
  547. return null;
  548. }
  549. }
  550. // for instance and import, the two NS's must be the same
  551. else if (referType != XSDDescription.CONTEXT_PREPARSE && callerTNS != currSchemaInfo.fTargetNamespace) {
  552. reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
  553. new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
  554. DOMUtil.getRoot(schemaRoot));
  555. return null;
  556. }
  557. }
  558. // now there is no caller/expected NS, it's an error for the referred
  559. // document to have a target namespace, unless we are preparsing a schema
  560. else if (currSchemaInfo.fTargetNamespace != null) {
  561. // set the target namespace of the description
  562. if (referType == XSDDescription.CONTEXT_PREPARSE) {
  563. desc.setTargetNamespace(currSchemaInfo.fTargetNamespace);
  564. callerTNS = currSchemaInfo.fTargetNamespace;
  565. }
  566. else {
  567. // the second index to the NS_ERROR_CODES array
  568. // if the caller/expected NS is absent, we use the second column
  569. int secondIdx = 1;
  570. reportSchemaError(NS_ERROR_CODES[referType][secondIdx],
  571. new Object [] {callerTNS, currSchemaInfo.fTargetNamespace},
  572. DOMUtil.getRoot(schemaRoot));
  573. return null;
  574. }
  575. }
  576. // the other cases (callerTNS == currSchemaInfo.fTargetNamespce == null)
  577. // are valid
  578. // a schema document can always access it's own target namespace
  579. currSchemaInfo.addAllowedNS(currSchemaInfo.fTargetNamespace);
  580. SchemaGrammar sg = null;
  581. if (referType == XSDDescription.CONTEXT_INCLUDE ||
  582. referType == XSDDescription.CONTEXT_REDEFINE) {
  583. sg = fGrammarBucket.getGrammar(currSchemaInfo.fTargetNamespace);
  584. }
  585. else {
  586. sg = new SchemaGrammar(currSchemaInfo.fTargetNamespace, desc.makeClone(), fSymbolTable);
  587. fGrammarBucket.putGrammar(sg);
  588. }
  589. // store the document and its location
  590. // REVISIT: don't expose the DOM tree
  591. //sg.addDocument(currSchemaInfo.fSchemaDoc, (String)fDoc2SystemId.get(currSchemaInfo));
  592. sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaDoc));
  593. fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
  594. Vector dependencies = new Vector();
  595. Element rootNode = DOMUtil.getRoot(schemaRoot);
  596. Document newSchemaRoot = null;
  597. for (Element child = DOMUtil.getFirstChildElement(rootNode);
  598. child != null;
  599. child = DOMUtil.getNextSiblingElement(child)) {
  600. String schemaNamespace=null;
  601. String schemaHint=null;
  602. String localName = DOMUtil.getLocalName(child);
  603. short refType = -1;
  604. if (localName.equals(SchemaSymbols.ELT_ANNOTATION))
  605. continue;
  606. else if (localName.equals(SchemaSymbols.ELT_IMPORT)) {
  607. refType = XSDDescription.CONTEXT_IMPORT;
  608. // have to handle some validation here too!
  609. // call XSAttributeChecker to fill in attrs
  610. Object[] importAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
  611. schemaHint = (String)importAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
  612. schemaNamespace = (String)importAttrs[XSAttributeChecker.ATTIDX_NAMESPACE];
  613. if (schemaNamespace != null)
  614. schemaNamespace = fSymbolTable.addSymbol(schemaNamespace);
  615. // a document can't import another document with the same namespace
  616. if (schemaNamespace == currSchemaInfo.fTargetNamespace) {
  617. reportSchemaError("src-import.1.1", new Object [] {schemaNamespace}, child);
  618. }
  619. // check contents and process optional annotations
  620. Element importChild = DOMUtil.getFirstChildElement(child);
  621. if(importChild != null ) {
  622. String importComponentType = DOMUtil.getLocalName(importChild);
  623. if (importComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
  624. // promoting annotations to parent component
  625. sg.addAnnotation(
  626. fElementTraverser.traverseAnnotationDecl(importChild, importAttrs, true, currSchemaInfo));
  627. } else {
  628. reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", importComponentType}, child);
  629. }
  630. if(DOMUtil.getNextSiblingElement(importChild) != null) {
  631. reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(importChild))}, child);
  632. }
  633. }
  634. fAttributeChecker.returnAttrArray(importAttrs, currSchemaInfo);
  635. // if this namespace has been imported by this document,
  636. // ignore the <import> statement
  637. if (currSchemaInfo.isAllowedNS(schemaNamespace))
  638. continue;
  639. // a schema document can access it's imported namespaces
  640. currSchemaInfo.addAllowedNS(schemaNamespace);
  641. // also record the fact that one namespace imports another one
  642. // convert null to ""
  643. String tns = null2EmptyString(currSchemaInfo.fTargetNamespace);
  644. // get all namespaces imported by this one
  645. Vector ins = (Vector)fImportMap.get(tns);
  646. // if no namespace was imported, create new Vector
  647. if (ins == null) {
  648. // record that this one imports other(s)
  649. fAllTNSs.addElement(tns);
  650. ins = new Vector();
  651. fImportMap.put(tns, ins);
  652. ins.addElement(schemaNamespace);
  653. }
  654. else if (!ins.contains(schemaNamespace)){
  655. ins.addElement(schemaNamespace);
  656. }
  657. fSchemaGrammarDescription.reset();
  658. fSchemaGrammarDescription.setContextType(XSDDescription.CONTEXT_IMPORT);
  659. fSchemaGrammarDescription.setBaseSystemId((String)fDoc2SystemId.get(schemaRoot));
  660. fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
  661. fSchemaGrammarDescription.setTargetNamespace(schemaNamespace);
  662. // if a grammar with the same namespace exists (or being
  663. // built), ignore this one (don't traverse it).
  664. if (findGrammar(fSchemaGrammarDescription) != null)
  665. continue;
  666. newSchemaRoot = resolveSchema(fSchemaGrammarDescription, false, child);
  667. }
  668. else if ((localName.equals(SchemaSymbols.ELT_INCLUDE)) ||
  669. (localName.equals(SchemaSymbols.ELT_REDEFINE))) {
  670. // validation for redefine/include will be the same here; just
  671. // make sure TNS is right (don't care about redef contents
  672. // yet).
  673. Object[] includeAttrs = fAttributeChecker.checkAttributes(child, true, currSchemaInfo);
  674. schemaHint = (String)includeAttrs[XSAttributeChecker.ATTIDX_SCHEMALOCATION];
  675. // store the namespace decls of the redefine element
  676. if (localName.equals(SchemaSymbols.ELT_REDEFINE)) {
  677. fRedefine2NSSupport.put(child, new SchemaNamespaceSupport(currSchemaInfo.fNamespaceSupport));
  678. }
  679. // check annotations. Must do this here to avoid having to
  680. // re-parse attributes later
  681. if(localName.equals(SchemaSymbols.ELT_INCLUDE)) {
  682. Element includeChild = DOMUtil.getFirstChildElement(child);
  683. if(includeChild != null ) {
  684. String includeComponentType = DOMUtil.getLocalName(includeChild);
  685. if (includeComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
  686. // promoting annotations to parent component
  687. sg.addAnnotation(
  688. fElementTraverser.traverseAnnotationDecl(includeChild, includeAttrs, true, currSchemaInfo));
  689. } else {
  690. reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", includeComponentType}, child);
  691. }
  692. if(DOMUtil.getNextSiblingElement(includeChild) != null) {
  693. reportSchemaError("s4s-elt-must-match.1", new Object [] {localName, "annotation?", DOMUtil.getLocalName(DOMUtil.getNextSiblingElement(includeChild))}, child);
  694. }
  695. }
  696. }
  697. else {
  698. for (Element redefinedChild = DOMUtil.getFirstChildElement(child);
  699. redefinedChild != null;
  700. redefinedChild = DOMUtil.getNextSiblingElement(redefinedChild)) {
  701. String redefinedComponentType = DOMUtil.getLocalName(redefinedChild);
  702. if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
  703. // promoting annotations to parent component
  704. sg.addAnnotation(
  705. fElementTraverser.traverseAnnotationDecl(redefinedChild, includeAttrs, true, currSchemaInfo));
  706. DOMUtil.setHidden(redefinedChild);
  707. }
  708. // catch all other content errors later
  709. }
  710. }
  711. fAttributeChecker.returnAttrArray(includeAttrs, currSchemaInfo);
  712. // schemaLocation is required on <include> and <redefine>
  713. if (schemaHint == null) {
  714. reportSchemaError("s4s-att-must-appear", new Object [] {
  715. "<include> or <redefine>", "schemaLocation"},
  716. child);
  717. }
  718. // pass the systemId of the current document as the base systemId
  719. boolean mustResolve = false;
  720. refType = XSDDescription.CONTEXT_INCLUDE;
  721. if(localName.equals(SchemaSymbols.ELT_REDEFINE)) {
  722. mustResolve = nonAnnotationContent(child);
  723. refType = XSDDescription.CONTEXT_REDEFINE;
  724. }
  725. fSchemaGrammarDescription.reset();
  726. fSchemaGrammarDescription.setContextType(refType);
  727. fSchemaGrammarDescription.setBaseSystemId((String)fDoc2SystemId.get(schemaRoot));
  728. fSchemaGrammarDescription.setLocationHints(new String[]{schemaHint});
  729. fSchemaGrammarDescription.setTargetNamespace(callerTNS);
  730. newSchemaRoot = resolveSchema(fSchemaGrammarDescription, mustResolve, child);
  731. schemaNamespace = currSchemaInfo.fTargetNamespace;
  732. }
  733. else {
  734. // no more possibility of schema references in well-formed
  735. // schema...
  736. break;
  737. }
  738. // If the schema is duplicate, we needn't call constructTrees() again.
  739. // To handle mutual <include>s
  740. XSDocumentInfo newSchemaInfo = null;
  741. if (fLastSchemaWasDuplicate) {
  742. newSchemaInfo = (XSDocumentInfo)fDoc2XSDocumentMap.get(newSchemaRoot);
  743. }
  744. else {
  745. newSchemaInfo = constructTrees(newSchemaRoot, schemaHint, fSchemaGrammarDescription);
  746. }
  747. if (localName.equals(SchemaSymbols.ELT_REDEFINE) &&
  748. newSchemaInfo != null) {
  749. // must record which schema we're redefining so that we can
  750. // rename the right things later!
  751. fRedefine2XSDMap.put(child, newSchemaInfo);
  752. }
  753. if (newSchemaRoot != null) {
  754. if (newSchemaInfo != null)
  755. dependencies.addElement(newSchemaInfo);
  756. newSchemaRoot = null;
  757. }
  758. }
  759. fDependencyMap.put(currSchemaInfo, dependencies);
  760. return currSchemaInfo;
  761. } // end constructTrees
  762. // This method builds registries for all globally-referenceable
  763. // names. A registry will be built for each symbol space defined
  764. // by the spec. It is also this method's job to rename redefined
  765. // components, and to record which components redefine others (so
  766. // that implicit redefinitions of groups and attributeGroups can be handled).
  767. protected void buildGlobalNameRegistries() {
  768. /* Starting with fRoot, we examine each child of the schema
  769. * element. Skipping all imports and includes, we record the names
  770. * of all other global components (and children of <redefine>). We
  771. * also put <redefine> names in a registry that we look through in
  772. * case something needs renaming. Once we're done with a schema we
  773. * set its Document node to hidden so that we don't try to traverse
  774. * it again; then we look to its Dependency map entry. We keep a
  775. * stack of schemas that we haven't yet finished processing; this
  776. * is a depth-first traversal.
  777. */
  778. Stack schemasToProcess = new Stack();
  779. schemasToProcess.push(fRoot);
  780. while (!schemasToProcess.empty()) {
  781. XSDocumentInfo currSchemaDoc =
  782. (XSDocumentInfo)schemasToProcess.pop();
  783. Document currDoc = currSchemaDoc.fSchemaDoc;
  784. if (DOMUtil.isHidden(currDoc)) {
  785. // must have processed this already!
  786. continue;
  787. }
  788. Element currRoot = DOMUtil.getRoot(currDoc);
  789. // process this schema's global decls
  790. boolean dependenciesCanOccur = true;
  791. for (Element globalComp =
  792. DOMUtil.getFirstChildElement(currRoot);
  793. globalComp != null;
  794. globalComp = DOMUtil.getNextSiblingElement(globalComp)) {
  795. // this loop makes sure the <schema> element ordering is
  796. // also valid.
  797. if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_ANNOTATION)) {
  798. //skip it; traverse it later
  799. continue;
  800. }
  801. else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_INCLUDE) ||
  802. DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_IMPORT)) {
  803. if (!dependenciesCanOccur) {
  804. reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
  805. }
  806. // we've dealt with this; mark as traversed
  807. DOMUtil.setHidden(globalComp);
  808. }
  809. else if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
  810. if (!dependenciesCanOccur) {
  811. reportSchemaError("s4s-elt-invalid-content.3", new Object [] {DOMUtil.getLocalName(globalComp)}, globalComp);
  812. }
  813. for (Element redefineComp = DOMUtil.getFirstChildElement(globalComp);
  814. redefineComp != null;
  815. redefineComp = DOMUtil.getNextSiblingElement(redefineComp)) {
  816. String lName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME);
  817. if (lName.length() == 0) // an error we'll catch later
  818. continue;
  819. String qName = currSchemaDoc.fTargetNamespace == null ?
  820. ","+lName:
  821. currSchemaDoc.fTargetNamespace +","+lName;
  822. String componentType = DOMUtil.getLocalName(redefineComp);
  823. if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
  824. checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, redefineComp, currSchemaDoc);
  825. // the check will have changed our name;
  826. String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
  827. // and all we need to do is error-check+rename our kkids:
  828. renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_ATTRIBUTEGROUP,
  829. lName, targetLName);
  830. }
  831. else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
  832. (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
  833. checkForDuplicateNames(qName, fUnparsedTypeRegistry, redefineComp, currSchemaDoc);
  834. // the check will have changed our name;
  835. String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME) + REDEF_IDENTIFIER;
  836. // and all we need to do is error-check+rename our kkids:
  837. if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
  838. renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_COMPLEXTYPE,
  839. lName, targetLName);
  840. }
  841. else { // must be simpleType
  842. renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_SIMPLETYPE,
  843. lName, targetLName);
  844. }
  845. }
  846. else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
  847. checkForDuplicateNames(qName, fUnparsedGroupRegistry, redefineComp, currSchemaDoc);
  848. // the check will have changed our name;
  849. String targetLName = DOMUtil.getAttrValue(redefineComp, SchemaSymbols.ATT_NAME)+REDEF_IDENTIFIER;
  850. // and all we need to do is error-check+rename our kids:
  851. renameRedefiningComponents(currSchemaDoc, redefineComp, SchemaSymbols.ELT_GROUP,
  852. lName, targetLName);
  853. }
  854. } // end march through <redefine> children
  855. // and now set as traversed
  856. //DOMUtil.setHidden(globalComp);
  857. }
  858. else {
  859. dependenciesCanOccur = false;
  860. String lName = DOMUtil.getAttrValue(globalComp, SchemaSymbols.ATT_NAME);
  861. if (lName.length() == 0) // an error we'll catch later
  862. continue;
  863. String qName = currSchemaDoc.fTargetNamespace == null?
  864. ","+lName:
  865. currSchemaDoc.fTargetNamespace +","+lName;
  866. String componentType = DOMUtil.getLocalName(globalComp);
  867. if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
  868. checkForDuplicateNames(qName, fUnparsedAttributeRegistry, globalComp, currSchemaDoc);
  869. }
  870. else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
  871. checkForDuplicateNames(qName, fUnparsedAttributeGroupRegistry, globalComp, currSchemaDoc);
  872. }
  873. else if ((componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) ||
  874. (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE))) {
  875. checkForDuplicateNames(qName, fUnparsedTypeRegistry, globalComp, currSchemaDoc);
  876. }
  877. else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
  878. checkForDuplicateNames(qName, fUnparsedElementRegistry, globalComp, currSchemaDoc);
  879. }
  880. else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
  881. checkForDuplicateNames(qName, fUnparsedGroupRegistry, globalComp, currSchemaDoc);
  882. }
  883. else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
  884. checkForDuplicateNames(qName, fUnparsedNotationRegistry, globalComp, currSchemaDoc);
  885. }
  886. }
  887. } // end for
  888. // now we're done with this one!
  889. DOMUtil.setHidden(currDoc);
  890. // now add the schemas this guy depends on
  891. Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
  892. for (int i = 0; i < currSchemaDepends.size(); i++) {
  893. schemasToProcess.push(currSchemaDepends.elementAt(i));
  894. }
  895. } // while
  896. } // end buildGlobalNameRegistries
  897. // Beginning at the first schema processing was requested for
  898. // (fRoot), this method
  899. // examines each child (global schema information item) of each
  900. // schema document (and of each <redefine> element)
  901. // corresponding to an XSDocumentInfo object. If the
  902. // readOnly field on that node has not been set, it calls an
  903. // appropriate traverser to traverse it. Once all global decls in
  904. // an XSDocumentInfo object have been traversed, it marks that object
  905. // as traversed (or hidden) in order to avoid infinite loops. It completes
  906. // when it has visited all XSDocumentInfo objects in the
  907. // DependencyMap and marked them as traversed.
  908. protected void traverseSchemas() {
  909. // the process here is very similar to that in
  910. // buildGlobalRegistries, except we can't set our schemas as
  911. // hidden for a second time; so make them all visible again
  912. // first!
  913. setSchemasVisible(fRoot);
  914. Stack schemasToProcess = new Stack();
  915. schemasToProcess.push(fRoot);
  916. while (!schemasToProcess.empty()) {
  917. XSDocumentInfo currSchemaDoc =
  918. (XSDocumentInfo)schemasToProcess.pop();
  919. Document currDoc = currSchemaDoc.fSchemaDoc;
  920. SchemaGrammar currSG = fGrammarBucket.getGrammar(currSchemaDoc.fTargetNamespace);
  921. if (DOMUtil.isHidden(currDoc)) {
  922. // must have processed this already!
  923. continue;
  924. }
  925. Element currRoot = DOMUtil.getRoot(currDoc);
  926. // traverse this schema's global decls
  927. for (Element globalComp =
  928. DOMUtil.getFirstVisibleChildElement(currRoot);
  929. globalComp != null;
  930. globalComp = DOMUtil.getNextVisibleSiblingElement(globalComp)) {
  931. // We'll always want to set this as hidden!
  932. DOMUtil.setHidden(globalComp);
  933. String componentType = DOMUtil.getLocalName(globalComp);
  934. // includes and imports will not show up here!
  935. if (DOMUtil.getLocalName(globalComp).equals(SchemaSymbols.ELT_REDEFINE)) {
  936. // use the namespace decls for the redefine, instead of for the parent <schema>
  937. currSchemaDoc.backupNSSupport((SchemaNamespaceSupport)fRedefine2NSSupport.get(globalComp));
  938. for (Element redefinedComp = DOMUtil.getFirstVisibleChildElement(globalComp);
  939. redefinedComp != null;
  940. redefinedComp = DOMUtil.getNextVisibleSiblingElement(redefinedComp)) {
  941. String redefinedComponentType = DOMUtil.getLocalName(redefinedComp);
  942. DOMUtil.setHidden(redefinedComp);
  943. if (redefinedComponentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
  944. fAttributeGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
  945. }
  946. else if (redefinedComponentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
  947. fComplexTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
  948. }
  949. else if (redefinedComponentType.equals(SchemaSymbols.ELT_GROUP)) {
  950. fGroupTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
  951. }
  952. else if (redefinedComponentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
  953. fSimpleTypeTraverser.traverseGlobal(redefinedComp, currSchemaDoc, currSG);
  954. }
  955. // annotations will have been processed already; this is now
  956. // unnecessary
  957. //else if (redefinedComponentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
  958. // fElementTraverser.traverseAnnotationDecl(redefinedComp, null, true, currSchemaDoc);
  959. //}
  960. else {
  961. reportSchemaError("s4s-elt-must-match.1", new Object [] {DOMUtil.getLocalName(globalComp), "(annotation | (simpleType | complexType | group | attributeGroup))*", redefinedComponentType}, redefinedComp);
  962. }
  963. } // end march through <redefine> children
  964. currSchemaDoc.restoreNSSupport();
  965. }
  966. else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
  967. fAttributeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  968. }
  969. else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
  970. fAttributeGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  971. }
  972. else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
  973. fComplexTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  974. }
  975. else if (componentType.equals(SchemaSymbols.ELT_ELEMENT)) {
  976. fElementTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  977. }
  978. else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
  979. fGroupTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  980. }
  981. else if (componentType.equals(SchemaSymbols.ELT_NOTATION)) {
  982. fNotationTraverser.traverse(globalComp, currSchemaDoc, currSG);
  983. }
  984. else if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
  985. fSimpleTypeTraverser.traverseGlobal(globalComp, currSchemaDoc, currSG);
  986. }
  987. else if (componentType.equals(SchemaSymbols.ELT_ANNOTATION)) {
  988. currSG.addAnnotation(fElementTraverser.traverseAnnotationDecl(globalComp, currSchemaDoc.getSchemaAttrs(), true, currSchemaDoc));
  989. }
  990. else {
  991. reportSchemaError("s4s-elt-invalid-content.1", new Object [] {SchemaSymbols.ELT_SCHEMA, DOMUtil.getLocalName(globalComp)}, globalComp);
  992. }
  993. } // end for
  994. // now we're done with this one!
  995. currSchemaDoc.returnSchemaAttrs();
  996. DOMUtil.setHidden(currDoc);
  997. // now add the schemas this guy depends on
  998. Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
  999. for (int i = 0; i < currSchemaDepends.size(); i++) {
  1000. schemasToProcess.push(currSchemaDepends.elementAt(i));
  1001. }
  1002. } // while
  1003. } // end traverseSchemas
  1004. // store whether we have reported an error about that no grammar
  1005. // is found for the given namespace uri
  1006. private Vector fReportedTNS = null;
  1007. // check whether we need to report an error against the given uri.
  1008. // if we have reported an error, then we don't need to report again;
  1009. // otherwise we reported the error, and remember this fact.
  1010. private final boolean needReportTNSError(String uri) {
  1011. if (fReportedTNS == null)
  1012. fReportedTNS = new Vector();
  1013. else if (fReportedTNS.contains(uri))
  1014. return false;
  1015. fReportedTNS.addElement(uri);
  1016. return true;
  1017. }
  1018. private static final String[] COMP_TYPE = {
  1019. null, // index 0
  1020. "attribute declaration",
  1021. "attribute group",
  1022. "element declaration",
  1023. "group",
  1024. "identity constraint",
  1025. "notation",
  1026. "type definition",
  1027. };
  1028. private static final String[] CIRCULAR_CODES = {
  1029. "Internal-Error",
  1030. "Internal-Error",
  1031. "src-attribute_group.3",
  1032. "e-props-correct.6",
  1033. "mg-props-correct.2",
  1034. "Internal-Error",
  1035. "Internal-Error",
  1036. "st-props-correct.2", //or ct-props-correct.3
  1037. };
  1038. // since it is forbidden for traversers to talk to each other
  1039. // directly (except wen a traverser encounters a local declaration),
  1040. // this provides a generic means for a traverser to call
  1041. // for the traversal of some declaration. An XSDocumentInfo is
  1042. // required because the XSDocumentInfo that the traverser is traversing
  1043. // may bear no relation to the one the handler is operating on.
  1044. // This method will:
  1045. // 1. See if a global definition matching declToTraverse exists;
  1046. // 2. if so, determine if there is a path from currSchema to the
  1047. // schema document where declToTraverse lives (i.e., do a lookup
  1048. // in DependencyMap);
  1049. // 3. depending on declType (which will be relevant to step 1 as
  1050. // well), call the appropriate traverser with the appropriate
  1051. // XSDocumentInfo object.
  1052. // This method returns whatever the traverser it called returned;
  1053. // this will be an Object of some kind
  1054. // that lives in the Grammar.
  1055. protected Object getGlobalDecl(XSDocumentInfo currSchema,
  1056. int declType,
  1057. QName declToTraverse,
  1058. Element elmNode) {
  1059. if (DEBUG_NODE_POOL) {
  1060. System.out.println("TRAVERSE_GL: "+declToTraverse.toString());
  1061. }
  1062. // from the schema spec, all built-in types are present in all schemas,
  1063. // so if the requested component is a type, and could be found in the
  1064. // default schema grammar, we should return that type.
  1065. // otherwise (since we would support user-defined schema grammar) we'll
  1066. // use the normal way to get the decl
  1067. if (declToTraverse.uri != null &&
  1068. declToTraverse.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
  1069. if (declType == TYPEDECL_TYPE) {
  1070. Object retObj = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(declToTraverse.localpart);
  1071. if (retObj != null)
  1072. return retObj;
  1073. }
  1074. }
  1075. // now check whether this document can access the requsted namespace
  1076. if (!currSchema.isAllowedNS(declToTraverse.uri)) {
  1077. // cannot get to this schema from the one containing the requesting decl
  1078. if (currSchema.needReportTNSError(declToTraverse.uri)) {
  1079. String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
  1080. reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaDoc), declToTraverse.uri, declToTraverse.rawname}, elmNode);
  1081. }
  1082. return null;
  1083. }
  1084. // check whether there is grammar for the requested namespace
  1085. SchemaGrammar sGrammar = fGrammarBucket.getGrammar(declToTraverse.uri);
  1086. if (sGrammar == null) {
  1087. if (needReportTNSError(declToTraverse.uri))
  1088. reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
  1089. return null;
  1090. }
  1091. // if there is such grammar, check whether the requested component is in the grammar
  1092. Object retObj = null;
  1093. switch (declType) {
  1094. case ATTRIBUTE_TYPE :
  1095. retObj = sGrammar.getGlobalAttributeDecl(declToTraverse.localpart);
  1096. break;
  1097. case ATTRIBUTEGROUP_TYPE :
  1098. retObj = sGrammar.getGlobalAttributeGroupDecl(declToTraverse.localpart);
  1099. break;
  1100. case ELEMENT_TYPE :
  1101. retObj = sGrammar.getGlobalElementDecl(declToTraverse.localpart);
  1102. break;
  1103. case GROUP_TYPE :
  1104. retObj = sGrammar.getGlobalGroupDecl(declToTraverse.localpart);
  1105. break;
  1106. case IDENTITYCONSTRAINT_TYPE :
  1107. retObj = sGrammar.getIDConstraintDecl(declToTraverse.localpart);
  1108. break;
  1109. case NOTATION_TYPE :
  1110. retObj = sGrammar.getGlobalNotationDecl(declToTraverse.localpart);
  1111. break;
  1112. case TYPEDECL_TYPE :
  1113. retObj = sGrammar.getGlobalTypeDecl(declToTraverse.localpart);
  1114. break;
  1115. }
  1116. // if the component is parsed, return it
  1117. if (retObj != null)
  1118. return retObj;
  1119. XSDocumentInfo schemaWithDecl = null;
  1120. Element decl = null;
  1121. // the component is not parsed, try to find a DOM element for it
  1122. String declKey = declToTraverse.uri == null? ","+declToTraverse.localpart:
  1123. declToTraverse.uri+","+declToTraverse.localpart;
  1124. switch (declType) {
  1125. case ATTRIBUTE_TYPE :
  1126. decl = (Element)fUnparsedAttributeRegistry.get(declKey);
  1127. break;
  1128. case ATTRIBUTEGROUP_TYPE :
  1129. decl = (Element)fUnparsedAttributeGroupRegistry.get(declKey);
  1130. break;
  1131. case ELEMENT_TYPE :
  1132. decl = (Element)fUnparsedElementRegistry.get(declKey);
  1133. break;
  1134. case GROUP_TYPE :
  1135. decl = (Element)fUnparsedGroupRegistry.get(declKey);
  1136. break;
  1137. case IDENTITYCONSTRAINT_TYPE :
  1138. decl = (Element)fUnparsedIdentityConstraintRegistry.get(declKey);
  1139. break;
  1140. case NOTATION_TYPE :
  1141. decl = (Element)fUnparsedNotationRegistry.get(declKey);
  1142. break;
  1143. case TYPEDECL_TYPE :
  1144. decl = (Element)fUnparsedTypeRegistry.get(declKey);
  1145. break;
  1146. default:
  1147. reportSchemaError("Internal-Error", new Object [] {"XSDHandler asked to locate component of type " + declType + "; it does not recognize this type!"}, elmNode);
  1148. }
  1149. // no DOM element found, so the component can't be located
  1150. if (decl == null) {
  1151. reportSchemaError("src-resolve", new Object[]{declToTraverse.rawname, COMP_TYPE[declType]}, elmNode);
  1152. return null;
  1153. }
  1154. // get the schema doc containing the component to be parsed
  1155. // it should always return non-null value, but since null-checking
  1156. // comes for free, let's be safe and check again
  1157. schemaWithDecl = findXSDocumentForDecl(currSchema, decl);
  1158. if (schemaWithDecl == null) {
  1159. // cannot get to this schema from the one containing the requesting decl
  1160. String code = declToTraverse.uri == null ? "src-resolve.4.1" : "src-resolve.4.2";
  1161. reportSchemaError(code, new Object[]{fDoc2SystemId.get(currSchema.fSchemaDoc), declToTraverse.uri, declToTraverse.rawname}, elmNode);
  1162. return null;
  1163. }
  1164. // a component is hidden, meaning either it's traversed, or being traversed.
  1165. // but we didn't find it in the grammar, so it's the latter case, and
  1166. // a circular reference. error!
  1167. if (DOMUtil.isHidden(decl)) {
  1168. String code = CIRCULAR_CODES[declType];
  1169. if (declType == TYPEDECL_TYPE) {
  1170. if (SchemaSymbols.ELT_COMPLEXTYPE.equals(DOMUtil.getLocalName(decl)))
  1171. code = "ct-props-correct.3";
  1172. }
  1173. // decl must not be null if we're here...
  1174. reportSchemaError(code, new Object [] {declToTraverse.prefix+":"+declToTraverse.localpart}, elmNode);
  1175. return null;
  1176. }
  1177. // hide the element node before traversing it
  1178. DOMUtil.setHidden(decl);
  1179. SchemaNamespaceSupport nsSupport = null;
  1180. // if the parent is <redefine> use the namespace delcs for it.
  1181. Element parent = DOMUtil.getParent(decl);
  1182. if (DOMUtil.getLocalName(parent).equals(SchemaSymbols.ELT_REDEFINE))
  1183. nsSupport = (SchemaNamespaceSupport)fRedefine2NSSupport.get(parent);
  1184. // back up the current SchemaNamespaceSupport, because we need to provide
  1185. // a fresh one to the traverseGlobal methods.
  1186. schemaWithDecl.backupNSSupport(nsSupport);
  1187. // traverse the referenced global component
  1188. switch (declType) {
  1189. case ATTRIBUTE_TYPE :
  1190. retObj = fAttributeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1191. break;
  1192. case ATTRIBUTEGROUP_TYPE :
  1193. retObj = fAttributeGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1194. break;
  1195. case ELEMENT_TYPE :
  1196. retObj = fElementTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1197. break;
  1198. case GROUP_TYPE :
  1199. retObj = fGroupTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1200. break;
  1201. case IDENTITYCONSTRAINT_TYPE :
  1202. // identity constraints should have been parsed already...
  1203. // we should never get here
  1204. retObj = null;
  1205. break;
  1206. case NOTATION_TYPE :
  1207. retObj = fNotationTraverser.traverse(decl, schemaWithDecl, sGrammar);
  1208. break;
  1209. case TYPEDECL_TYPE :
  1210. if (DOMUtil.getLocalName(decl).equals(SchemaSymbols.ELT_COMPLEXTYPE))
  1211. retObj = fComplexTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1212. else
  1213. retObj = fSimpleTypeTraverser.traverseGlobal(decl, schemaWithDecl, sGrammar);
  1214. }
  1215. // restore the previous SchemaNamespaceSupport, so that the caller can get
  1216. // proper namespace binding.
  1217. schemaWithDecl.restoreNSSupport();
  1218. return retObj;
  1219. } // getGlobalDecl(XSDocumentInfo, int, QName): Object
  1220. // This method determines whether there is a group
  1221. // (attributeGroup) which the given one has redefined by
  1222. // restriction. If so, it returns it; else it returns null.
  1223. // @param type: whether what's been redefined is an
  1224. // attributeGroup or a group;
  1225. // @param name: the QName of the component doing the redefining.
  1226. // @param currSchema: schema doc in which the redefining component lives.
  1227. // @return: Object representing decl redefined if present, null
  1228. // otherwise.
  1229. Object getGrpOrAttrGrpRedefinedByRestriction(int type, QName name, XSDocumentInfo currSchema, Element elmNode) {
  1230. String realName = name.uri != null?name.uri+","+name.localpart:
  1231. ","+name.localpart;
  1232. String nameToFind = null;
  1233. switch (type) {
  1234. case ATTRIBUTEGROUP_TYPE:
  1235. nameToFind = (String)fRedefinedRestrictedAttributeGroupRegistry.get(realName);
  1236. break;
  1237. case GROUP_TYPE:
  1238. nameToFind = (String)fRedefinedRestrictedGroupRegistry.get(realName);
  1239. break;
  1240. default:
  1241. return null;
  1242. }
  1243. if (nameToFind == null) return null;
  1244. int commaPos = nameToFind.indexOf(",");
  1245. QName qNameToFind = new QName(XMLSymbols.EMPTY_STRING, nameToFind.substring(commaPos+1),
  1246. nameToFind.substring(commaPos), (commaPos == 0)? null : nameToFind.substring(0, commaPos));
  1247. Object retObj = getGlobalDecl(currSchema, type, qNameToFind, elmNode);
  1248. if(retObj == null) {
  1249. switch (type) {
  1250. case ATTRIBUTEGROUP_TYPE:
  1251. reportSchemaError("src-redefine.7.2.1", new Object []{name.localpart}, elmNode);
  1252. break;
  1253. case GROUP_TYPE:
  1254. reportSchemaError("src-redefine.6.2.1", new Object []{name.localpart}, elmNode);
  1255. break;
  1256. }
  1257. return null;
  1258. }
  1259. return retObj;
  1260. } // getGrpOrAttrGrpRedefinedByRestriction(int, QName, XSDocumentInfo): Object
  1261. // Since ID constraints can occur in local elements, unless we
  1262. // wish to completely traverse all our DOM trees looking for ID
  1263. // constraints while we're building our global name registries,
  1264. // which seems terribly inefficient, we need to resolve keyrefs
  1265. // after all parsing is complete. This we can simply do by running through
  1266. // fIdentityConstraintRegistry and calling traverseKeyRef on all
  1267. // of the KeyRef nodes. This unfortunately removes this knowledge
  1268. // from the elementTraverser class (which must ignore keyrefs),
  1269. // but there seems to be no efficient way around this...
  1270. protected void resolveKeyRefs() {
  1271. for (int i=0; i<fKeyrefStackPos; i++) {
  1272. Document keyrefDoc = DOMUtil.getDocument(fKeyrefs[i]);
  1273. XSDocumentInfo keyrefSchemaDoc = (XSDocumentInfo)fDoc2XSDocumentMap.get(keyrefDoc);
  1274. keyrefSchemaDoc.fNamespaceSupport.makeGlobal();
  1275. keyrefSchemaDoc.fNamespaceSupport.setEffectiveContext( fKeyrefNamespaceContext[i] );
  1276. SchemaGrammar keyrefGrammar = fGrammarBucket.getGrammar(keyrefSchemaDoc.fTargetNamespace);
  1277. // need to set <keyref> to hidden before traversing it,
  1278. // because it has global scope
  1279. DOMUtil.setHidden(fKeyrefs[i]);
  1280. fKeyrefTraverser.traverse(fKeyrefs[i], fKeyrefElems[i], keyrefSchemaDoc, keyrefGrammar);
  1281. }
  1282. } // end resolveKeyRefs
  1283. // an accessor method. Just makes sure callers
  1284. // who want the Identity constraint registry vaguely know what they're about.
  1285. protected Hashtable getIDRegistry() {
  1286. return fUnparsedIdentityConstraintRegistry;
  1287. }
  1288. // This method squirrels away <keyref> declarations--along with the element
  1289. // decls and namespace bindings they might find handy.
  1290. protected void storeKeyRef (Element keyrefToStore, XSDocumentInfo schemaDoc,
  1291. XSElementDecl currElemDecl) {
  1292. String keyrefName = DOMUtil.getAttrValue(keyrefToStore, SchemaSymbols.ATT_NAME);
  1293. if (keyrefName.length() != 0) {
  1294. String keyrefQName = schemaDoc.fTargetNamespace == null?
  1295. "," + keyrefName: schemaDoc.fTargetNamespace+","+keyrefName;
  1296. checkForDuplicateNames(keyrefQName, fUnparsedIdentityConstraintRegistry, keyrefToStore, schemaDoc);
  1297. }
  1298. // now set up all the registries we'll need...
  1299. // check array sizes
  1300. if (fKeyrefStackPos == fKeyrefs.length) {
  1301. Element [] elemArray = new Element [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
  1302. System.arraycopy(fKeyrefs, 0, elemArray, 0, fKeyrefStackPos);
  1303. fKeyrefs = elemArray;
  1304. XSElementDecl [] declArray = new XSElementDecl [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT];
  1305. System.arraycopy(fKeyrefElems, 0, declArray, 0, fKeyrefStackPos);
  1306. fKeyrefElems = declArray;
  1307. String[][] stringArray = new String [fKeyrefStackPos + INC_KEYREF_STACK_AMOUNT][];
  1308. System.arraycopy(fKeyrefNamespaceContext, 0, stringArray, 0, fKeyrefStackPos);
  1309. fKeyrefNamespaceContext = stringArray;
  1310. }
  1311. fKeyrefs[fKeyrefStackPos] = keyrefToStore;
  1312. fKeyrefElems[fKeyrefStackPos] = currElemDecl;
  1313. fKeyrefNamespaceContext[fKeyrefStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
  1314. } // storeKeyref (Element, XSDocumentInfo, XSElementDecl): void
  1315. /**
  1316. * resolveSchema method is responsible for resolving location of the schema (using XMLEntityResolver),
  1317. * and if it was succefully resolved getting the schema Document.
  1318. * @param desc
  1319. * @param mustResolve
  1320. * @param referElement
  1321. * @return A schema Document or null.
  1322. */
  1323. private Document resolveSchema(XSDDescription desc,
  1324. boolean mustResolve, Element referElement) {
  1325. XMLInputSource schemaSource=null;
  1326. try {
  1327. schemaSource = XMLSchemaLoader.resolveDocument(desc, fLocationPairs, fEntityResolver);
  1328. }
  1329. catch (IOException ex) {
  1330. if (mustResolve) {
  1331. reportSchemaError("schema_reference.4",
  1332. new Object[]{desc.getLocationHints()[0]},
  1333. referElement);
  1334. }
  1335. else {
  1336. reportSchemaWarning("schema_reference.4",
  1337. new Object[]{desc.getLocationHints()[0]},
  1338. referElement);
  1339. }
  1340. }
  1341. return getSchema(desc.getTargetNamespace(),
  1342. schemaSource.toSource(), mustResolve, desc.getContextType(), referElement);
  1343. } // getSchema(String, String, String, boolean, short): Document
  1344. /**
  1345. * getSchemaDocument method uses XMLInputSource to parse a schema document.
  1346. * @param schemaNamespace
  1347. * @param schemaSource
  1348. * @param mustResolve
  1349. * @param referType
  1350. * @param referElement
  1351. * @return A schema Document.
  1352. */
  1353. private Document getSchema(String schemaNamespace, Source schemaSource,
  1354. boolean mustResolve, short referType, Element referElement) {
  1355. boolean hasInput = true;
  1356. // contents of this method will depend on the system we adopt for entity resolution--i.e., XMLEntityHandler, EntityHandler, etc.
  1357. Document schemaDoc = null;
  1358. try {
  1359. // when the system id and byte stream and character stream
  1360. // of the input source are all null, it's
  1361. // impossible to find the schema document. so we skip in
  1362. // this case. otherwise we'll receive some NPE or
  1363. // file not found errors. but schemaHint=="" is perfectly
  1364. // legal for import.
  1365. if (schemaSource != null ) {
  1366. // When the system id of the input source is used, first try to
  1367. // expand it, and check whether the same document has been
  1368. // parsed before. If so, return the document corresponding to
  1369. // that system id.
  1370. XSDKey key = null;
  1371. String schemaId = null;
  1372. if (referType != XSDDescription.CONTEXT_PREPARSE){
  1373. schemaId = schemaSource.getSystemId();
  1374. key = new XSDKey(schemaId, referType, schemaNamespace);
  1375. if ((schemaDoc = (Document)fTraversed.get(key)) != null) {
  1376. fLastSchemaWasDuplicate = true;
  1377. return schemaDoc;
  1378. }
  1379. }
  1380. if( schemaSource instanceof XMLInputSourceAdaptor ) {
  1381. // If this is the first schema this Handler has
  1382. // parsed, it has to construct a DOMParser
  1383. fSchemaParser.parse(((XMLInputSourceAdaptor)schemaSource).fSource);
  1384. schemaDoc = fSchemaParser.getDocument();
  1385. } else
  1386. if( schemaSource instanceof DOMSource ) {
  1387. // Xerces needs a special kind of DOM, so
  1388. // we have to clone it into that form otherwise
  1389. // things won't work.
  1390. // TODO: this dependency to a particular DOM implementation
  1391. // should be fixed.
  1392. // but then SchemaDOM doesn't support importNode,
  1393. // so here we just rely on IdentityTransformer
  1394. try {
  1395. Transformer t = TransformerFactory.newInstance().newTransformer();
  1396. SchemaDOMParser p = new SchemaDOMParser(fErrorReporter);
  1397. t.transform( schemaSource, new SAXResult(new SAX2XNI(p)) );
  1398. schemaDoc = p.getDocument();
  1399. } catch( TransformerException e ) {
  1400. // impossible.
  1401. e.printStackTrace();
  1402. throw new InternalError();
  1403. }
  1404. } else
  1405. if( schemaSource instanceof StreamSource ) {
  1406. fSchemaParser.parse(new XMLInputSource((StreamSource)schemaSource));
  1407. schemaDoc = fSchemaParser.getDocument();
  1408. } else
  1409. if( schemaSource instanceof SAXSource ) {
  1410. SAXSource ss = (SAXSource)schemaSource;
  1411. XMLReader reader = ss.getXMLReader();
  1412. if(reader==null) {
  1413. reader = new SAXParser();
  1414. try {
  1415. reader.setFeature("http://xml.org/sax/features/namespaces",true);
  1416. reader.setFeature("http://xml.org/sax/features/namespace-prefixes",true);
  1417. } catch( SAXException e ) {
  1418. // impossible
  1419. e.printStackTrace();
  1420. throw new InternalError();
  1421. }
  1422. }
  1423. SchemaDOMParser p = new SchemaDOMParser(fErrorReporter);
  1424. reader.setContentHandler(new SAX2XNI(p));
  1425. reader.setErrorHandler(fErrorReporter.getSAXErrorHandler());
  1426. try {
  1427. reader.parse(ss.getInputSource());
  1428. schemaDoc = p.getDocument();
  1429. } catch( SAXException e ) {
  1430. ; // should have already been reported.
  1431. }
  1432. } else {
  1433. throw new IllegalArgumentException(schemaSource.getClass().getName());
  1434. }
  1435. // now we need to store the mapping information from system id
  1436. // to the document. also from the document to the system id.
  1437. if (key != null)
  1438. fTraversed.put(key, schemaDoc );
  1439. if (schemaId != null)
  1440. fDoc2SystemId.put(schemaDoc, schemaId );
  1441. fLastSchemaWasDuplicate = false;
  1442. return schemaDoc;
  1443. }
  1444. else {
  1445. hasInput = false;
  1446. }
  1447. }
  1448. catch (IOException ex) {
  1449. }
  1450. // either an error occured (exception), or empty input source was
  1451. // returned, we need to report an error or a warning
  1452. if (mustResolve) {
  1453. if (hasInput) {
  1454. reportSchemaError("schema_reference.4",
  1455. new Object[]{schemaSource.getSystemId()},
  1456. referElement);
  1457. }
  1458. else {
  1459. reportSchemaError("schema_reference.4",
  1460. new Object[]{schemaSource == null ? "" : schemaSource.getSystemId()},
  1461. referElement);
  1462. }
  1463. }
  1464. fLastSchemaWasDuplicate = false;
  1465. return null;
  1466. } // getSchema(String, XMLInputSource, boolean, boolean): Document
  1467. // initialize all the traversers.
  1468. // this should only need to be called once during the construction
  1469. // of this object; it creates the traversers that will be used to
  1470. // construct schemaGrammars.
  1471. private void createTraversers() {
  1472. fAttributeChecker = new XSAttributeChecker(this);
  1473. fAttributeGroupTraverser = new XSDAttributeGroupTraverser(this, fAttributeChecker);
  1474. fAttributeTraverser = new XSDAttributeTraverser(this, fAttributeChecker);
  1475. fComplexTypeTraverser = new XSDComplexTypeTraverser(this, fAttributeChecker);
  1476. fElementTraverser = new XSDElementTraverser(this, fAttributeChecker);
  1477. fGroupTraverser = new XSDGroupTraverser(this, fAttributeChecker);
  1478. fKeyrefTraverser = new XSDKeyrefTraverser(this, fAttributeChecker);
  1479. fNotationTraverser = new XSDNotationTraverser(this, fAttributeChecker);
  1480. fSimpleTypeTraverser = new XSDSimpleTypeTraverser(this, fAttributeChecker);
  1481. fUniqueOrKeyTraverser = new XSDUniqueOrKeyTraverser(this, fAttributeChecker);
  1482. fWildCardTraverser = new XSDWildcardTraverser(this, fAttributeChecker);
  1483. } // createTraversers()
  1484. // before parsing a schema, need to clear registries associated with
  1485. // parsing schemas
  1486. void prepareForParse() {
  1487. fTraversed.clear();
  1488. fDoc2SystemId.clear();
  1489. fLastSchemaWasDuplicate = false;
  1490. }
  1491. // before traversing a schema's parse tree, need to reset all traversers and
  1492. // clear all registries
  1493. void prepareForTraverse() {
  1494. fUnparsedAttributeRegistry.clear();
  1495. fUnparsedAttributeGroupRegistry.clear();
  1496. fUnparsedElementRegistry.clear();
  1497. fUnparsedGroupRegistry.clear();
  1498. fUnparsedIdentityConstraintRegistry.clear();
  1499. fUnparsedNotationRegistry.clear();
  1500. fUnparsedTypeRegistry.clear();
  1501. fXSDocumentInfoRegistry.clear();
  1502. fDependencyMap.clear();
  1503. fDoc2XSDocumentMap.clear();
  1504. fRedefine2XSDMap.clear();
  1505. fRedefine2NSSupport.clear();
  1506. fAllTNSs.removeAllElements();
  1507. fImportMap.clear();
  1508. fRoot = null;
  1509. // clear local element stack
  1510. for (int i = 0; i < fLocalElemStackPos; i++) {
  1511. fParticle[i] = null;
  1512. fLocalElementDecl[i] = null;
  1513. fLocalElemNamespaceContext[i] = null;
  1514. }
  1515. fLocalElemStackPos = 0;
  1516. // and do same for keyrefs.
  1517. for (int i = 0; i < fKeyrefStackPos; i++) {
  1518. fKeyrefs[i] = null;
  1519. fKeyrefElems[i] = null;
  1520. fKeyrefNamespaceContext[i] = null;
  1521. }
  1522. fKeyrefStackPos = 0;
  1523. // create traversers if necessary
  1524. if (fAttributeChecker == null) {
  1525. createTraversers();
  1526. }
  1527. // reset traversers
  1528. fAttributeChecker.reset(fSymbolTable);
  1529. fAttributeGroupTraverser.reset(fSymbolTable);
  1530. fAttributeTraverser.reset(fSymbolTable);
  1531. fComplexTypeTraverser.reset(fSymbolTable);
  1532. fElementTraverser.reset(fSymbolTable);
  1533. fGroupTraverser.reset(fSymbolTable);
  1534. fKeyrefTraverser.reset(fSymbolTable);
  1535. fNotationTraverser.reset(fSymbolTable);
  1536. fSimpleTypeTraverser.reset(fSymbolTable);
  1537. fUniqueOrKeyTraverser.reset(fSymbolTable);
  1538. fWildCardTraverser.reset(fSymbolTable);
  1539. fRedefinedRestrictedAttributeGroupRegistry.clear();
  1540. fRedefinedRestrictedGroupRegistry.clear();
  1541. }
  1542. public void setDeclPool (XSDeclarationPool declPool){
  1543. fDeclPool = declPool;
  1544. }
  1545. public void reset(XMLComponentManager componentManager) {
  1546. // set symbol table
  1547. fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
  1548. fSecureProcessing = null;
  1549. if( componentManager!=null ) {
  1550. try {
  1551. fSecureProcessing = (SecurityManager) componentManager.getProperty(SECURE_PROCESSING);
  1552. } catch (XMLConfigurationException xmlConfigurationException) {
  1553. ;
  1554. }
  1555. }
  1556. //set entity resolver
  1557. fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
  1558. XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
  1559. if (er != null)
  1560. fSchemaParser.setEntityResolver(er);
  1561. // set error reporter
  1562. fErrorReporter =
  1563. (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
  1564. try {
  1565. XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
  1566. // Setting a parser property can be much more expensive
  1567. // than checking its value. Don't set the ERROR_HANDLER
  1568. // property unless it's actually changed.
  1569. if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
  1570. fSchemaParser.setProperty(ERROR_HANDLER, currErrorHandler);
  1571. }
  1572. } catch (XMLConfigurationException e) {
  1573. }
  1574. try {
  1575. fSchemaParser.setFeature(
  1576. CONTINUE_AFTER_FATAL_ERROR,
  1577. fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
  1578. } catch (XMLConfigurationException e) {
  1579. }
  1580. try {
  1581. fSchemaParser.setFeature(
  1582. ALLOW_JAVA_ENCODINGS,
  1583. componentManager.getFeature(ALLOW_JAVA_ENCODINGS));
  1584. } catch (XMLConfigurationException e) {
  1585. }
  1586. try {
  1587. fSchemaParser.setFeature(
  1588. STANDARD_URI_CONFORMANT_FEATURE,
  1589. componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE));
  1590. } catch (XMLConfigurationException e) {
  1591. }
  1592. try {
  1593. fGrammarPool =
  1594. (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
  1595. } catch (XMLConfigurationException e) {
  1596. fGrammarPool = null;
  1597. }
  1598. // security features
  1599. try {
  1600. fSchemaParser.setFeature( DISALLOW_DOCTYPE,
  1601. componentManager.getFeature(DISALLOW_DOCTYPE));
  1602. } catch (XMLConfigurationException e) {
  1603. }
  1604. try {
  1605. Object security = componentManager.getProperty(SECURITY_MANAGER);
  1606. if (security != null){
  1607. fSchemaParser.setProperty(SECURITY_MANAGER, security);
  1608. }
  1609. } catch (XMLConfigurationException e) {
  1610. }
  1611. } // reset(XMLComponentManager)
  1612. /**
  1613. * Traverse all the deferred local elements. This method should be called
  1614. * by traverseSchemas after we've done with all the global declarations.
  1615. */
  1616. void traverseLocalElements() {
  1617. fElementTraverser.fDeferTraversingLocalElements = false;
  1618. for (int i = 0; i < fLocalElemStackPos; i++) {
  1619. Element currElem = fLocalElementDecl[i];
  1620. XSDocumentInfo currSchema = (XSDocumentInfo)fDoc2XSDocumentMap.get(DOMUtil.getDocument(currElem));
  1621. SchemaGrammar currGrammar = fGrammarBucket.getGrammar(currSchema.fTargetNamespace);
  1622. fElementTraverser.traverseLocal (fParticle[i], currElem, currSchema, currGrammar, fAllContext[i], fParent[i]);
  1623. // If it's an empty particle, remove it from the containing component.
  1624. if (fParticle[i].fType == XSParticleDecl.PARTICLE_EMPTY) {
  1625. XSModelGroupImpl group;
  1626. if (fParent[i] instanceof XSComplexTypeDecl)
  1627. group = (XSModelGroupImpl)((XSComplexTypeDecl)fParent[i]).getParticle().getTerm();
  1628. else
  1629. group = ((XSGroupDecl)fParent[i]).fModelGroup;
  1630. removeParticle(group, fParticle[i]);
  1631. }
  1632. }
  1633. }
  1634. private boolean removeParticle(XSModelGroupImpl group, XSParticleDecl particle) {
  1635. XSParticleDecl member;
  1636. for (int i = 0; i < group.fParticleCount; i++) {
  1637. member = group.fParticles[i];
  1638. if (member == particle) {
  1639. for (int j = i; j < group.fParticleCount-1; j++)
  1640. group.fParticles[j] = group.fParticles[j+1];
  1641. group.fParticleCount--;
  1642. return true;
  1643. }
  1644. if (member.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
  1645. if (removeParticle((XSModelGroupImpl)member.fValue, particle))
  1646. return true;
  1647. }
  1648. }
  1649. return false;
  1650. }
  1651. // the purpose of this method is to keep up-to-date structures
  1652. // we'll need for the feferred traversal of local elements.
  1653. void fillInLocalElemInfo(Element elmDecl,
  1654. XSDocumentInfo schemaDoc,
  1655. int allContextFlags,
  1656. XSObject parent,
  1657. XSParticleDecl particle) {
  1658. // if the stack is full, increase the size
  1659. if (fParticle.length == fLocalElemStackPos) {
  1660. // increase size
  1661. XSParticleDecl[] newStackP = new XSParticleDecl[fLocalElemStackPos+INC_STACK_SIZE];
  1662. System.arraycopy(fParticle, 0, newStackP, 0, fLocalElemStackPos);
  1663. fParticle = newStackP;
  1664. Element[] newStackE = new Element[fLocalElemStackPos+INC_STACK_SIZE];
  1665. System.arraycopy(fLocalElementDecl, 0, newStackE, 0, fLocalElemStackPos);
  1666. fLocalElementDecl = newStackE;
  1667. int[] newStackI = new int[fLocalElemStackPos+INC_STACK_SIZE];
  1668. System.arraycopy(fAllContext, 0, newStackI, 0, fLocalElemStackPos);
  1669. fAllContext = newStackI;
  1670. XSObject[] newStackC = new XSObject[fLocalElemStackPos+INC_STACK_SIZE];
  1671. System.arraycopy(fParent, 0, newStackC, 0, fLocalElemStackPos);
  1672. fParent = newStackC;
  1673. String [][] newStackN = new String [fLocalElemStackPos+INC_STACK_SIZE][];
  1674. System.arraycopy(fLocalElemNamespaceContext, 0, newStackN, 0, fLocalElemStackPos);
  1675. fLocalElemNamespaceContext = newStackN;
  1676. }
  1677. fParticle[fLocalElemStackPos] = particle;
  1678. fLocalElementDecl[fLocalElemStackPos] = elmDecl;
  1679. fAllContext[fLocalElemStackPos] = allContextFlags;
  1680. fParent[fLocalElemStackPos] = parent;
  1681. fLocalElemNamespaceContext[fLocalElemStackPos++] = schemaDoc.fNamespaceSupport.getEffectiveLocalContext();
  1682. } // end fillInLocalElemInfo(...)
  1683. /** This method makes sure that
  1684. * if this component is being redefined that it lives in the
  1685. * right schema. It then renames the component correctly. If it
  1686. * detects a collision--a duplicate definition--then it complains.
  1687. * Note that redefines must be handled carefully: if there
  1688. * is a collision, it may be because we're redefining something we know about
  1689. * or because we've found the thing we're redefining.
  1690. */
  1691. void checkForDuplicateNames(String qName,
  1692. Hashtable registry, Element currComp,
  1693. XSDocumentInfo currSchema) {
  1694. Object objElem = null;
  1695. // REVISIT: when we add derivation checking, we'll have to make
  1696. // sure that ID constraint collisions don't necessarily result in error messages.
  1697. if ((objElem = registry.get(qName)) == null) {
  1698. // just add it in!
  1699. registry.put(qName, currComp);
  1700. }
  1701. else {
  1702. Element collidingElem = (Element)objElem;
  1703. if (collidingElem == currComp) return;
  1704. Element elemParent = null;
  1705. XSDocumentInfo redefinedSchema = null;
  1706. // case where we've collided with a redefining element
  1707. // (the parent of the colliding element is a redefine)
  1708. boolean collidedWithRedefine = true;
  1709. if ((DOMUtil.getLocalName((elemParent = DOMUtil.getParent(collidingElem))).equals(SchemaSymbols.ELT_REDEFINE))) {
  1710. redefinedSchema = (XSDocumentInfo)(fRedefine2XSDMap.get(elemParent));
  1711. // case where we're a redefining element.
  1712. }
  1713. else if ((DOMUtil.getLocalName(DOMUtil.getParent(currComp)).equals(SchemaSymbols.ELT_REDEFINE))) {
  1714. redefinedSchema = (XSDocumentInfo)(fDoc2XSDocumentMap.get(DOMUtil.getDocument(collidingElem)));
  1715. collidedWithRedefine = false;
  1716. }
  1717. if (redefinedSchema != null) { //redefinition involved somehow
  1718. // If both components belong to the same document then
  1719. // report an error and return.
  1720. if (fDoc2XSDocumentMap.get(DOMUtil.getDocument(collidingElem)) == currSchema) {
  1721. reportSchemaError("sch-props-correct.2", new Object[]{qName}, currComp);
  1722. return;
  1723. }
  1724. String newName = qName.substring(qName.lastIndexOf(',')+1)+REDEF_IDENTIFIER;
  1725. if (redefinedSchema == currSchema) { // object comp. okay here
  1726. // now have to do some renaming...
  1727. currComp.setAttribute(SchemaSymbols.ATT_NAME, newName);
  1728. if (currSchema.fTargetNamespace == null)
  1729. registry.put(","+newName, currComp);
  1730. else
  1731. registry.put(currSchema.fTargetNamespace+","+newName, currComp);
  1732. // and take care of nested redefines by calling recursively:
  1733. if (currSchema.fTargetNamespace == null)
  1734. checkForDuplicateNames(","+newName, registry, currComp, currSchema);
  1735. else
  1736. checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema);
  1737. }
  1738. else { // we may be redefining the wrong schema
  1739. if (collidedWithRedefine) {
  1740. if (currSchema.fTargetNamespace == null)
  1741. checkForDuplicateNames(","+newName, registry, currComp, currSchema);
  1742. else
  1743. checkForDuplicateNames(currSchema.fTargetNamespace+","+newName, registry, currComp, currSchema);
  1744. }
  1745. else {
  1746. // error that redefined element in wrong schema
  1747. reportSchemaError("sch-props-correct.2", new Object [] {qName}, currComp);
  1748. }
  1749. }
  1750. }
  1751. else {
  1752. // we've just got a flat-out collision
  1753. reportSchemaError("sch-props-correct.2", new Object []{qName}, currComp);
  1754. }
  1755. }
  1756. } // checkForDuplicateNames(String, Hashtable, Element, XSDocumentInfo):void
  1757. // the purpose of this method is to take the component of the
  1758. // specified type and rename references to itself so that they
  1759. // refer to the object being redefined. It takes special care of
  1760. // <group>s and <attributeGroup>s to ensure that information
  1761. // relating to implicit restrictions is preserved for those
  1762. // traversers.
  1763. private void renameRedefiningComponents(XSDocumentInfo currSchema,
  1764. Element child, String componentType,
  1765. String oldName, String newName) {
  1766. if (componentType.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
  1767. Element grandKid = DOMUtil.getFirstChildElement(child);
  1768. if (grandKid == null) {
  1769. reportSchemaError("src-redefine.5.a.a", null, child);
  1770. }
  1771. else {
  1772. String grandKidName = DOMUtil.getLocalName(grandKid);
  1773. if (grandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
  1774. grandKid = DOMUtil.getNextSiblingElement(grandKid);
  1775. }
  1776. if (grandKid == null) {
  1777. reportSchemaError("src-redefine.5.a.a", null, child);
  1778. }
  1779. else {
  1780. grandKidName = DOMUtil.getLocalName(grandKid);
  1781. if (!grandKidName.equals(SchemaSymbols.ELT_RESTRICTION)) {
  1782. reportSchemaError("src-redefine.5.a.b", new Object[]{grandKidName}, child);
  1783. }
  1784. else {
  1785. Object[] attrs = fAttributeChecker.checkAttributes(grandKid, false, currSchema);
  1786. QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
  1787. if (derivedBase == null ||
  1788. derivedBase.uri != currSchema.fTargetNamespace ||
  1789. !derivedBase.localpart.equals(oldName)) {
  1790. reportSchemaError("src-redefine.5.a.c",
  1791. new Object[]{grandKidName,
  1792. (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
  1793. + "," + oldName},
  1794. child);
  1795. }
  1796. else {
  1797. // now we have to do the renaming...
  1798. if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
  1799. grandKid.setAttribute( SchemaSymbols.ATT_BASE,
  1800. derivedBase.prefix + ":" + newName );
  1801. else
  1802. grandKid.setAttribute( SchemaSymbols.ATT_BASE, newName );
  1803. // return true;
  1804. }
  1805. fAttributeChecker.returnAttrArray(attrs, currSchema);
  1806. }
  1807. }
  1808. }
  1809. }
  1810. else if (componentType.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
  1811. Element grandKid = DOMUtil.getFirstChildElement(child);
  1812. if (grandKid == null) {
  1813. reportSchemaError("src-redefine.5.b.a", null, child);
  1814. }
  1815. else {
  1816. if (DOMUtil.getLocalName(grandKid).equals(SchemaSymbols.ELT_ANNOTATION)) {
  1817. grandKid = DOMUtil.getNextSiblingElement(grandKid);
  1818. }
  1819. if (grandKid == null) {
  1820. reportSchemaError("src-redefine.5.b.a", null, child);
  1821. }
  1822. else {
  1823. // have to go one more level down; let another pass worry whether complexType is valid.
  1824. Element greatGrandKid = DOMUtil.getFirstChildElement(grandKid);
  1825. if (greatGrandKid == null) {
  1826. reportSchemaError("src-redefine.5.b.b", null, grandKid);
  1827. }
  1828. else {
  1829. String greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
  1830. if (greatGrandKidName.equals(SchemaSymbols.ELT_ANNOTATION)) {
  1831. greatGrandKid = DOMUtil.getNextSiblingElement(greatGrandKid);
  1832. }
  1833. if (greatGrandKid == null) {
  1834. reportSchemaError("src-redefine.5.b.b", null, grandKid);
  1835. }
  1836. else {
  1837. greatGrandKidName = DOMUtil.getLocalName(greatGrandKid);
  1838. if (!greatGrandKidName.equals(SchemaSymbols.ELT_RESTRICTION) &&
  1839. !greatGrandKidName.equals(SchemaSymbols.ELT_EXTENSION)) {
  1840. reportSchemaError("src-redefine.5.b.c", new Object[]{greatGrandKidName}, greatGrandKid);
  1841. }
  1842. else {
  1843. Object[] attrs = fAttributeChecker.checkAttributes(greatGrandKid, false, currSchema);
  1844. QName derivedBase = (QName)attrs[XSAttributeChecker.ATTIDX_BASE];
  1845. if (derivedBase == null ||
  1846. derivedBase.uri != currSchema.fTargetNamespace ||
  1847. !derivedBase.localpart.equals(oldName)) {
  1848. reportSchemaError("src-redefine.5.b.d",
  1849. new Object[]{greatGrandKidName,
  1850. (currSchema.fTargetNamespace==null?"":currSchema.fTargetNamespace)
  1851. + "," + oldName},
  1852. greatGrandKid);
  1853. }
  1854. else {
  1855. // now we have to do the renaming...
  1856. if (derivedBase.prefix != null && derivedBase.prefix.length() > 0)
  1857. greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
  1858. derivedBase.prefix + ":" + newName );
  1859. else
  1860. greatGrandKid.setAttribute( SchemaSymbols.ATT_BASE,
  1861. newName );
  1862. // return true;
  1863. }
  1864. }
  1865. }
  1866. }
  1867. }
  1868. }
  1869. }
  1870. else if (componentType.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
  1871. String processedBaseName = (currSchema.fTargetNamespace == null)?
  1872. ","+oldName:currSchema.fTargetNamespace+","+oldName;
  1873. int attGroupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
  1874. if (attGroupRefsCount > 1) {
  1875. reportSchemaError("src-redefine.7.1", new Object []{new Integer(attGroupRefsCount)}, child);
  1876. }
  1877. else if (attGroupRefsCount == 1) {
  1878. // return true;
  1879. }
  1880. else
  1881. if (currSchema.fTargetNamespace == null)
  1882. fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, ","+newName);
  1883. else
  1884. fRedefinedRestrictedAttributeGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
  1885. }
  1886. else if (componentType.equals(SchemaSymbols.ELT_GROUP)) {
  1887. String processedBaseName = (currSchema.fTargetNamespace == null)?
  1888. ","+oldName:currSchema.fTargetNamespace+","+oldName;
  1889. int groupRefsCount = changeRedefineGroup(processedBaseName, componentType, newName, child, currSchema);
  1890. if (groupRefsCount > 1) {
  1891. reportSchemaError("src-redefine.6.1.1", new Object []{new Integer(groupRefsCount)}, child);
  1892. }
  1893. else if (groupRefsCount == 1) {
  1894. // return true;
  1895. }
  1896. else {
  1897. if (currSchema.fTargetNamespace == null)
  1898. fRedefinedRestrictedGroupRegistry.put(processedBaseName, ","+newName);
  1899. else
  1900. fRedefinedRestrictedGroupRegistry.put(processedBaseName, currSchema.fTargetNamespace+","+newName);
  1901. }
  1902. }
  1903. else {
  1904. reportSchemaError("Internal-Error", new Object [] {"could not handle this particular <redefine> please submit your schemas and instance document in a bug report!"}, child);
  1905. }
  1906. // if we get here then we must have reported an error and failed somewhere...
  1907. // return false;
  1908. } // renameRedefiningComponents(XSDocumentInfo, Element, String, String, String):void
  1909. // this method takes a name of the form a:b, determines the URI mapped
  1910. // to by a in the current SchemaNamespaceSupport object, and returns this
  1911. // information in the form (nsURI,b) suitable for lookups in the global
  1912. // decl Hashtables.
  1913. // REVISIT: should have it return QName, instead of String. this would
  1914. // save lots of string concatenation time. we can use
  1915. // QName#equals() to compare two QNames, and use QName directly
  1916. // as a key to the SymbolHash.
  1917. // And when the DV's are ready to return compiled values from
  1918. // validate() method, we should just call QNameDV.validate()
  1919. // in this method.
  1920. private String findQName(String name, XSDocumentInfo schemaDoc) {
  1921. SchemaNamespaceSupport currNSMap = schemaDoc.fNamespaceSupport;
  1922. int colonPtr = name.indexOf(':');
  1923. String prefix = XMLSymbols.EMPTY_STRING;
  1924. if (colonPtr > 0)
  1925. prefix = name.substring(0, colonPtr);
  1926. String uri = currNSMap.getURI(fSymbolTable.addSymbol(prefix));
  1927. String localpart = (colonPtr == 0)?name:name.substring(colonPtr+1);
  1928. if (prefix == XMLSymbols.EMPTY_STRING && uri == null && schemaDoc.fIsChameleonSchema)
  1929. uri = schemaDoc.fTargetNamespace;
  1930. if (uri == null)
  1931. return ","+localpart;
  1932. return uri+","+localpart;
  1933. } // findQName(String, XSDocumentInfo): String
  1934. // This function looks among the children of curr for an element of type elementSought.
  1935. // If it finds one, it evaluates whether its ref attribute contains a reference
  1936. // to originalQName. If it does, it returns 1 + the value returned by
  1937. // calls to itself on all other children. In all other cases it returns 0 plus
  1938. // the sum of the values returned by calls to itself on curr's children.
  1939. // It also resets the value of ref so that it will refer to the renamed type from the schema
  1940. // being redefined.
  1941. private int changeRedefineGroup(String originalQName, String elementSought,
  1942. String newName, Element curr, XSDocumentInfo schemaDoc) {
  1943. int result = 0;
  1944. for (Element child = DOMUtil.getFirstChildElement(curr);
  1945. child != null; child = DOMUtil.getNextSiblingElement(child)) {
  1946. String name = DOMUtil.getLocalName(child);
  1947. if (!name.equals(elementSought))
  1948. result += changeRedefineGroup(originalQName, elementSought, newName, child, schemaDoc);
  1949. else {
  1950. String ref = child.getAttribute( SchemaSymbols.ATT_REF );
  1951. if (ref.length() != 0) {
  1952. String processedRef = findQName(ref, schemaDoc);
  1953. if (originalQName.equals(processedRef)) {
  1954. String prefix = XMLSymbols.EMPTY_STRING;
  1955. int colonptr = ref.indexOf(":");
  1956. if (colonptr > 0) {
  1957. prefix = ref.substring(0,colonptr);
  1958. child.setAttribute(SchemaSymbols.ATT_REF, prefix + ":" + newName);
  1959. }
  1960. else
  1961. child.setAttribute(SchemaSymbols.ATT_REF, newName);
  1962. result++;
  1963. if (elementSought.equals(SchemaSymbols.ELT_GROUP)) {
  1964. String minOccurs = child.getAttribute( SchemaSymbols.ATT_MINOCCURS );
  1965. String maxOccurs = child.getAttribute( SchemaSymbols.ATT_MAXOCCURS );
  1966. if (!((maxOccurs.length() == 0 || maxOccurs.equals("1"))
  1967. && (minOccurs.length() == 0 || minOccurs.equals("1")))) {
  1968. reportSchemaError("src-redefine.6.1.2", new Object [] {ref}, child);
  1969. }
  1970. }
  1971. }
  1972. } // if ref was null some other stage of processing will flag the error
  1973. }
  1974. }
  1975. return result;
  1976. } // changeRedefineGroup
  1977. // this method returns the XSDocumentInfo object that contains the
  1978. // component corresponding to decl. If components from this
  1979. // document cannot be referred to from those of currSchema, this
  1980. // method returns null; it's up to the caller to throw an error.
  1981. // @param: currSchema: the XSDocumentInfo object containing the
  1982. // decl ref'ing us.
  1983. // @param: decl: the declaration being ref'd.
  1984. private XSDocumentInfo findXSDocumentForDecl(XSDocumentInfo currSchema,
  1985. Element decl) {
  1986. if (DEBUG_NODE_POOL) {
  1987. System.out.println("DOCUMENT NS:"+ currSchema.fTargetNamespace+" hashcode:"+ ((Object)currSchema.fSchemaDoc).hashCode());
  1988. }
  1989. Document declDoc = DOMUtil.getDocument(decl);
  1990. Object temp = fDoc2XSDocumentMap.get(declDoc);
  1991. if (temp == null) {
  1992. // something went badly wrong; we don't know this doc?
  1993. return null;
  1994. }
  1995. XSDocumentInfo declDocInfo = (XSDocumentInfo)temp;
  1996. return declDocInfo;
  1997. /*********
  1998. Logic here is unnecessary after schema WG's recent decision to allow
  1999. schema components from one document to refer to components of any other,
  2000. so long as there's some include/import/redefine path amongst them.
  2001. If they rver reverse this decision the code's right here though... - neilg
  2002. // now look in fDependencyMap to see if this is reachable
  2003. if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
  2004. return declDocInfo;
  2005. }
  2006. // obviously the requesting doc didn't include, redefine or
  2007. // import the one containing decl...
  2008. return null;
  2009. **********/
  2010. } // findXSDocumentForDecl(XSDocumentInfo, Element): XSDocumentInfo
  2011. // returns whether more than <annotation>s occur in children of elem
  2012. private boolean nonAnnotationContent(Element elem) {
  2013. for(Element child = DOMUtil.getFirstChildElement(elem); child != null; child = DOMUtil.getNextSiblingElement(child)) {
  2014. if(!(DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION))) return true;
  2015. }
  2016. return false;
  2017. } // nonAnnotationContent(Element): boolean
  2018. private void setSchemasVisible(XSDocumentInfo startSchema) {
  2019. if (DOMUtil.isHidden(startSchema.fSchemaDoc)) {
  2020. // make it visible
  2021. DOMUtil.setVisible(startSchema.fSchemaDoc);
  2022. Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema);
  2023. for (int i = 0; i < dependingSchemas.size(); i++) {
  2024. setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
  2025. }
  2026. }
  2027. // if it's visible already than so must be its children
  2028. } // setSchemasVisible(XSDocumentInfo): void
  2029. private SimpleLocator xl = new SimpleLocator();
  2030. /**
  2031. * Extract location information from an Element node, and create a
  2032. * new SimpleLocator object from such information. Returning null means
  2033. * no information can be retrieved from the element.
  2034. */
  2035. public SimpleLocator element2Locator(Element e) {
  2036. if (!( e instanceof ElementImpl))
  2037. return null;
  2038. SimpleLocator l = new SimpleLocator();
  2039. return element2Locator(e, l) ? l : null;
  2040. }
  2041. /**
  2042. * Extract location information from an Element node, store such
  2043. * information in the passed-in SimpleLocator object, then return
  2044. * true. Returning false means can't extract or store such information.
  2045. */
  2046. public boolean element2Locator(Element e, SimpleLocator l) {
  2047. if (l == null)
  2048. return false;
  2049. if (e instanceof ElementImpl) {
  2050. ElementImpl ele = (ElementImpl)e;
  2051. // get system id from document object
  2052. Document doc = ele.getOwnerDocument();
  2053. String sid = (String)fDoc2SystemId.get(doc);
  2054. // line/column numbers are stored in the element node
  2055. int line = ele.getLineNumber();
  2056. int column = ele.getColumnNumber();
  2057. l.setValues(sid, sid, line, column);
  2058. return true;
  2059. }
  2060. return false;
  2061. }
  2062. void reportSchemaError(String key, Object[] args, Element ele) {
  2063. if (element2Locator(ele, xl)) {
  2064. fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
  2065. key, args, XMLErrorReporter.SEVERITY_ERROR);
  2066. }
  2067. else {
  2068. fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
  2069. key, args, XMLErrorReporter.SEVERITY_ERROR);
  2070. }
  2071. }
  2072. void reportSchemaWarning(String key, Object[] args, Element ele) {
  2073. if (element2Locator(ele, xl)) {
  2074. fErrorReporter.reportError(xl, XSMessageFormatter.SCHEMA_DOMAIN,
  2075. key, args, XMLErrorReporter.SEVERITY_WARNING);
  2076. }
  2077. else {
  2078. fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
  2079. key, args, XMLErrorReporter.SEVERITY_WARNING);
  2080. }
  2081. }
  2082. /**
  2083. * used to identify a reference to a schema document
  2084. * if the same document is referenced twice with the same key, then
  2085. * we only need to parse it once.
  2086. *
  2087. * When 2 XSDKey's are compared, the following table can be used to
  2088. * determine whether they are equal:
  2089. * inc red imp pre ins
  2090. * inc N/L ? N/L N/L N/L
  2091. * red ? N/L ? ? ?
  2092. * imp N/L ? N/P N/P N/P
  2093. * pre N/L ? N/P N/P N/P
  2094. * ins N/L ? N/P N/P N/P
  2095. *
  2096. * Where: N/L: duplicate when they have the same namespace and location.
  2097. * ? : not clear from the spec.
  2098. * REVISIT: to simplify the process, also considering
  2099. * it's very rare, we treat them as not duplicate.
  2100. * N/P: not possible. imp/pre/ins are referenced by namespace.
  2101. * when the first time we encounter a schema document for a
  2102. * namespace, we create a grammar and store it in the grammar
  2103. * bucket. when we see another reference to the same namespace,
  2104. * we first check whether a grammar with the same namespace is
  2105. * already in the bucket, which is true in this case, so we
  2106. * won't create another XSDKey.
  2107. *
  2108. * Conclusion from the table: two XSDKey's are duplicate only when all of
  2109. * the following are true:
  2110. * 1. They are both "redefine", or neither is "redefine";
  2111. * 2. They have the same namespace;
  2112. * 3. They have the same non-null location.
  2113. *
  2114. * About 3: if neither has a non-null location, then it's the case where
  2115. * 2 input streams are provided, but no system ID is provided. We can't tell
  2116. * whether the 2 streams have the same content, so we treat them as not
  2117. * duplicate.
  2118. */
  2119. private static class XSDKey {
  2120. String systemId;
  2121. short referType;
  2122. // for inclue/redefine, this is the enclosing namespace
  2123. // for import/preparse/instance, this is the target namespace
  2124. String referNS;
  2125. XSDKey(String systemId, short referType, String referNS) {
  2126. this.systemId = systemId;
  2127. this.referType = referType;
  2128. this.referNS = referNS;
  2129. }
  2130. public int hashCode() {
  2131. // according to the description at the beginning of this class,
  2132. // we use the hashcode of the namespace as the hashcoe of this key.
  2133. return referNS == null ? 0 : referNS.hashCode();
  2134. }
  2135. public boolean equals(Object obj) {
  2136. if (!(obj instanceof XSDKey)) {
  2137. return false;
  2138. }
  2139. XSDKey key = (XSDKey)obj;
  2140. // condition 1: both are redefine
  2141. if (referType == XSDDescription.CONTEXT_REDEFINE ||
  2142. key.referType == XSDDescription.CONTEXT_REDEFINE) {
  2143. if (referType != key.referType)
  2144. return false;
  2145. }
  2146. // condition 2: same namespace
  2147. if (referNS != key.referNS)
  2148. return false;
  2149. // condition 3: same non-null locatoin
  2150. if (systemId == null || !systemId.equals(key.systemId)) {
  2151. return false;
  2152. }
  2153. return true;
  2154. }
  2155. }
  2156. } // XSDHandler