1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-2003 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) 2001, 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;
  58. import com.sun.org.apache.xerces.internal.xs.XSConstants;
  59. import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  60. import com.sun.org.apache.xerces.internal.xni.QName;
  61. import java.util.Hashtable;
  62. import java.util.Vector;
  63. /**
  64. * To store and validate information about substitutionGroup
  65. *
  66. * @author Sandy Gao, IBM
  67. *
  68. * @version $Id: SubstitutionGroupHandler.java,v 1.14 2003/11/11 20:14:58 sandygao Exp $
  69. */
  70. public class SubstitutionGroupHandler {
  71. // grammar resolver
  72. XSGrammarBucket fGrammarBucket;
  73. /**
  74. * Default constructor
  75. */
  76. public SubstitutionGroupHandler(XSGrammarBucket grammarBucket) {
  77. fGrammarBucket = grammarBucket;
  78. }
  79. // 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3
  80. // check whether one element decl matches an element with the given qname
  81. public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) {
  82. if (element.localpart == exemplar.fName &&
  83. element.uri == exemplar.fTargetNamespace) {
  84. return exemplar;
  85. }
  86. // if the exemplar is not a global element decl, then it's not possible
  87. // to be substituted by another element.
  88. if (exemplar.fScope != XSConstants.SCOPE_GLOBAL)
  89. return null;
  90. // if the decl blocks substitution, return false
  91. if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0)
  92. return null;
  93. // get grammar of the element
  94. SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri);
  95. if (sGrammar == null)
  96. return null;
  97. // get the decl for the element
  98. XSElementDecl eDecl = sGrammar.getGlobalElementDecl(element.localpart);
  99. if (eDecl == null)
  100. return null;
  101. // and check by using substitutionGroup information
  102. if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock))
  103. return eDecl;
  104. return null;
  105. }
  106. // 3.3.6 Substitution Group OK (Transitive)
  107. // check whether element can substitute exemplar
  108. protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) {
  109. // For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true:
  110. // 1. D and C are the same element declaration.
  111. if (element == exemplar)
  112. return true;
  113. // 2 All of the following must be true:
  114. // 2.1 The blocking constraint does not contain substitution.
  115. if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0)
  116. return false;
  117. // 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . .
  118. XSElementDecl subGroup = element.fSubGroup;
  119. while (subGroup != null && subGroup != exemplar) {
  120. subGroup = subGroup.fSubGroup;
  121. }
  122. if (subGroup == null)
  123. return false;
  124. // 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}.
  125. // prepare the combination of {derivation method} and
  126. // {disallowed substitution}
  127. short devMethod = 0, blockConstraint = blockingConstraint;
  128. // element.fType should be derived from exemplar.fType
  129. // add derivation methods of derived types to devMethod;
  130. // add block of base types to blockConstraint.
  131. XSTypeDefinition type = element.fType;
  132. while (type != exemplar.fType && type != SchemaGrammar.fAnyType) {
  133. if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
  134. devMethod |= ((XSComplexTypeDecl)type).fDerivedBy;
  135. else
  136. devMethod |= XSConstants.DERIVATION_RESTRICTION;
  137. type = type.getBaseType();
  138. // type == null means the current type is anySimpleType,
  139. // whose base type should be anyType
  140. if (type == null)
  141. type = SchemaGrammar.fAnyType;
  142. if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
  143. blockConstraint |= ((XSComplexTypeDecl)type).fBlock;
  144. }
  145. if (type != exemplar.fType)
  146. return false;
  147. if ((devMethod & blockConstraint) != 0)
  148. return false;
  149. return true;
  150. }
  151. // check whether element is in exemplar's substitution group
  152. public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) {
  153. // [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows:
  154. // Define PSG, the potential substitution group for HEAD, as follows:
  155. // 1 The element declaration itself is in PSG;
  156. // 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself.
  157. // HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true:
  158. // 1 Its {abstract} is false.
  159. // 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6).
  160. return substitutionGroupOK(element, exemplar, exemplar.fBlock);
  161. }
  162. // to store substitution group information
  163. // the key to the hashtable is an element decl, and the value is
  164. // - a Vector, which contains all elements that has this element as their
  165. // substitution group affilication
  166. // - an array of OneSubGroup, which contains its substitution group before block.
  167. Hashtable fSubGroupsB = new Hashtable();
  168. private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0];
  169. // The real substitution groups (after "block")
  170. Hashtable fSubGroups = new Hashtable();
  171. /**
  172. * clear the internal registry of substitutionGroup information
  173. */
  174. public void reset() {
  175. fSubGroupsB.clear();
  176. fSubGroups.clear();
  177. }
  178. /**
  179. * add a list of substitution group information.
  180. */
  181. public void addSubstitutionGroup(XSElementDecl[] elements) {
  182. XSElementDecl subHead, element;
  183. Vector subGroup;
  184. // for all elements with substitution group affiliation
  185. for (int i = elements.length-1; i >= 0; i--) {
  186. element = elements[i];
  187. subHead = element.fSubGroup;
  188. // check whether this an entry for this element
  189. subGroup = (Vector)fSubGroupsB.get(subHead);
  190. if (subGroup == null) {
  191. // if not, create a new one
  192. subGroup = new Vector();
  193. fSubGroupsB.put(subHead, subGroup);
  194. }
  195. // add to the vactor
  196. subGroup.addElement(element);
  197. }
  198. }
  199. /**
  200. * get all elements that can substitute the given element,
  201. * according to the spec, we shouldn't consider the {block} constraints.
  202. *
  203. * from the spec, substitution group of a given element decl also contains
  204. * the element itself. but the array returned from this method doesn't
  205. * containt this element.
  206. */
  207. public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) {
  208. // If we already have sub group for this element, just return it.
  209. Object subGroup = fSubGroups.get(element);
  210. if (subGroup != null)
  211. return (XSElementDecl[])subGroup;
  212. // Otherwise, get all potential sub group elements
  213. // (without considering "block" on this element
  214. OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup());
  215. int len = groupB.length, rlen = 0;
  216. XSElementDecl[] ret = new XSElementDecl[len];
  217. // For each of such elements, check whether the derivation methods
  218. // overlap with "block". If not, add it to the sub group
  219. for (int i = 0 ; i < len; i++) {
  220. if ((element.fBlock & groupB[i].dMethod) == 0)
  221. ret[rlen++] = groupB[i].sub;
  222. }
  223. // Resize the array if necessary
  224. if (rlen < len) {
  225. XSElementDecl[] ret1 = new XSElementDecl[rlen];
  226. System.arraycopy(ret, 0, ret1, 0, rlen);
  227. ret = ret1;
  228. }
  229. // Store the subgroup
  230. fSubGroups.put(element, ret);
  231. return ret;
  232. }
  233. // Get potential sub group element (without considering "block")
  234. private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) {
  235. Object subGroup = fSubGroupsB.get(element);
  236. // substitution group for this one is empty
  237. if (subGroup == null) {
  238. fSubGroupsB.put(element, EMPTY_VECTOR);
  239. return EMPTY_VECTOR;
  240. }
  241. // we've already calculated the element, just return.
  242. if (subGroup instanceof OneSubGroup[])
  243. return (OneSubGroup[])subGroup;
  244. // we only have the *direct* substitutions
  245. Vector group = (Vector)subGroup, newGroup = new Vector();
  246. OneSubGroup[] group1;
  247. // then for each of the direct substitutions, get its substitution
  248. // group, and combine the groups together.
  249. short dMethod, bMethod, dSubMethod, bSubMethod;
  250. for (int i = group.size()-1, j; i >= 0; i--) {
  251. // Check whether this element is blocked. If so, ignore it.
  252. XSElementDecl sub = (XSElementDecl)group.elementAt(i);
  253. if (!getDBMethods(sub.fType, element.fType, methods))
  254. continue;
  255. // Remember derivation methods and blocks from the types
  256. dMethod = methods.dMethod;
  257. bMethod = methods.bMethod;
  258. // Add this one to potential group
  259. newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod));
  260. // Get potential group for this element
  261. group1 = getSubGroupB(sub, methods);
  262. for (j = group1.length-1; j >= 0; j--) {
  263. // For each of them, check whether it's blocked (by type)
  264. dSubMethod = (short)(dMethod | group1[j].dMethod);
  265. bSubMethod = (short)(bMethod | group1[j].bMethod);
  266. // Ignore it if it's blocked
  267. if ((dSubMethod & bSubMethod) != 0)
  268. continue;
  269. newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod));
  270. }
  271. }
  272. // Convert to an array
  273. OneSubGroup[] ret = new OneSubGroup[newGroup.size()];
  274. for (int i = newGroup.size()-1; i >= 0; i--) {
  275. ret[i] = (OneSubGroup)newGroup.elementAt(i);
  276. }
  277. // Store the potential sub group
  278. fSubGroupsB.put(element, ret);
  279. return ret;
  280. }
  281. private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb,
  282. OneSubGroup methods) {
  283. short dMethod = 0, bMethod = 0;
  284. while (typed != typeb && typed != SchemaGrammar.fAnyType) {
  285. if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
  286. dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy;
  287. else
  288. dMethod |= XSConstants.DERIVATION_RESTRICTION;
  289. typed = typed.getBaseType();
  290. // type == null means the current type is anySimpleType,
  291. // whose base type should be anyType
  292. if (typed == null)
  293. typed = SchemaGrammar.fAnyType;
  294. if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
  295. bMethod |= ((XSComplexTypeDecl)typed).fBlock;
  296. }
  297. // No derivation relation, or blocked, return false
  298. if (typed != typeb || (dMethod & bMethod) != 0)
  299. return false;
  300. // Remember the derivation methods and blocks, return true.
  301. methods.dMethod = dMethod;
  302. methods.bMethod = bMethod;
  303. return true;
  304. }
  305. // Record the information about how one element substitute another one
  306. private static final class OneSubGroup {
  307. OneSubGroup() {}
  308. OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) {
  309. this.sub = sub;
  310. this.dMethod = dMethod;
  311. this.bMethod = bMethod;
  312. }
  313. // The element that substitutes another one
  314. XSElementDecl sub;
  315. // The combination of all derivation methods from sub's type to
  316. // the head's type
  317. short dMethod;
  318. // The combination of {block} of the types in the derivation chain
  319. // excluding sub's type
  320. short bMethod;
  321. }
  322. } // class SubstitutionGroupHandler