1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-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) 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.models;
  58. import com.sun.org.apache.xerces.internal.impl.dtd.models.CMNode;
  59. import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  60. import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
  61. import com.sun.org.apache.xerces.internal.impl.xs.XSDeclarationPool;
  62. import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
  63. import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl;
  64. import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
  65. /**
  66. * This class constructs content models for a given grammar.
  67. *
  68. * @author Elena Litani, IBM
  69. * @author Sandy Gao, IBM
  70. *
  71. * @version $Id: CMBuilder.java,v 1.21 2004/02/03 17:27:45 sandygao Exp $
  72. */
  73. public class CMBuilder {
  74. // REVISIT: should update the decl pool to cache XSCM objects too
  75. private XSDeclarationPool fDeclPool = null;
  76. // It never changes, so a static member is good enough
  77. private static XSEmptyCM fEmptyCM = new XSEmptyCM();
  78. // needed for DFA construction
  79. private int fLeafCount;
  80. // needed for UPA
  81. private int fParticleCount;
  82. //Factory to create Bin, Uni, Leaf nodes
  83. private CMNodeFactory fNodeFactory ;
  84. public CMBuilder(CMNodeFactory nodeFactory) {
  85. fDeclPool = null;
  86. fNodeFactory = nodeFactory ;
  87. }
  88. public void setDeclPool(XSDeclarationPool declPool) {
  89. fDeclPool = declPool;
  90. }
  91. /**
  92. * Get content model for the a given type
  93. *
  94. * @param typeDecl get content model for which complex type
  95. * @return a content model validator
  96. */
  97. public XSCMValidator getContentModel(XSComplexTypeDecl typeDecl) {
  98. // for complex type with empty or simple content,
  99. // there is no content model validator
  100. short contentType = typeDecl.getContentType();
  101. if (contentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE ||
  102. contentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY) {
  103. return null;
  104. }
  105. XSParticleDecl particle = (XSParticleDecl)typeDecl.getParticle();
  106. // if the content is element only or mixed, but no particle
  107. // is defined, return the empty content model
  108. if (particle == null)
  109. return fEmptyCM;
  110. // if the content model contains "all" model group,
  111. // we create an "all" content model, otherwise a DFA content model
  112. XSCMValidator cmValidator = null;
  113. if (particle.fType == XSParticleDecl.PARTICLE_MODELGROUP &&
  114. ((XSModelGroupImpl)particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL) {
  115. cmValidator = createAllCM(particle);
  116. }
  117. else {
  118. cmValidator = createDFACM(particle);
  119. }
  120. //now we are throught building content model and have passed sucessfully of the nodecount check
  121. //if set by the application
  122. fNodeFactory.resetNodeCount() ;
  123. // if the validator returned is null, it means there is nothing in
  124. // the content model, so we return the empty content model.
  125. if (cmValidator == null)
  126. cmValidator = fEmptyCM;
  127. return cmValidator;
  128. }
  129. XSCMValidator createAllCM(XSParticleDecl particle) {
  130. if (particle.fMaxOccurs == 0)
  131. return null;
  132. // get the model group, and add all children of it to the content model
  133. XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue;
  134. // create an all content model. the parameter indicates whether
  135. // the <all> itself is optional
  136. XSAllCM allContent = new XSAllCM(particle.fMinOccurs == 0, group.fParticleCount);
  137. for (int i = 0; i < group.fParticleCount; i++) {
  138. // add the element decl to the all content model
  139. allContent.addElement((XSElementDecl)group.fParticles[i].fValue,
  140. group.fParticles[i].fMinOccurs == 0);
  141. }
  142. return allContent;
  143. }
  144. XSCMValidator createDFACM(XSParticleDecl particle) {
  145. fLeafCount = 0;
  146. fParticleCount = 0;
  147. // convert particle tree to CM tree
  148. CMNode node = buildSyntaxTree(particle);
  149. if (node == null)
  150. return null;
  151. // build DFA content model from the CM tree
  152. return new XSDFACM(node, fLeafCount);
  153. }
  154. // 1. convert particle tree to CM tree:
  155. // 2. expand all occurrence values: a{n, unbounded} -> a, a, ..., a+
  156. // a{n, m} -> a, a, ..., a?, a?, ...
  157. // 3. convert model groups (a, b, c, ...) or (a | b | c | ...) to
  158. // binary tree: (((a,b),c),...) or (((a|b)|c)|...)
  159. // 4. make sure each leaf node (XSCMLeaf) has a distinct position
  160. private CMNode buildSyntaxTree(XSParticleDecl particle) {
  161. int maxOccurs = particle.fMaxOccurs;
  162. int minOccurs = particle.fMinOccurs;
  163. short type = particle.fType;
  164. CMNode nodeRet = null;
  165. if ((type == XSParticleDecl.PARTICLE_WILDCARD) ||
  166. (type == XSParticleDecl.PARTICLE_ELEMENT)) {
  167. // (task 1) element and wildcard particles should be converted to
  168. // leaf nodes
  169. // REVISIT: Make a clone of the leaf particle, so that if there
  170. // are two references to the same group, we have two different
  171. // leaf particles for the same element or wildcard decl.
  172. // This is useful for checking UPA.
  173. nodeRet = fNodeFactory.getCMLeafNode(particle.fType, particle.fValue, fParticleCount++, fLeafCount++);
  174. // (task 2) expand occurrence values
  175. nodeRet = expandContentModel(nodeRet, minOccurs, maxOccurs);
  176. }
  177. else if (type == XSParticleDecl.PARTICLE_MODELGROUP) {
  178. // (task 1,3) convert model groups to binary trees
  179. XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue;
  180. CMNode temp = null;
  181. // when the model group is a choice of more than one particles, but
  182. // only one of the particle is not empty, (for example
  183. // <choice>
  184. // <sequence/>
  185. // <element name="e"/>
  186. // </choice>
  187. // ) we can't not return that one particle ("e"). instead, we should
  188. // treat such particle as optional ("e?").
  189. // the following boolean variable is true when there are at least
  190. // 2 non-empty children.
  191. boolean twoChildren = false;
  192. for (int i = 0; i < group.fParticleCount; i++) {
  193. // first convert each child to a CM tree
  194. temp = buildSyntaxTree(group.fParticles[i]);
  195. // then combine them using binary operation
  196. if (temp != null) {
  197. if (nodeRet == null) {
  198. nodeRet = temp;
  199. }
  200. else {
  201. nodeRet = fNodeFactory.getCMBinOpNode(group.fCompositor, nodeRet, temp);
  202. // record the fact that there are at least 2 children
  203. twoChildren = true;
  204. }
  205. }
  206. }
  207. // (task 2) expand occurrence values
  208. if (nodeRet != null) {
  209. // when the group is "choice", there is only one non-empty
  210. // child, and the group had more than one children, we need
  211. // to create a zero-or-one (optional) node for the non-empty
  212. // particle.
  213. if (group.fCompositor == XSModelGroupImpl.MODELGROUP_CHOICE &&
  214. !twoChildren && group.fParticleCount > 1) {
  215. nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, nodeRet);
  216. }
  217. nodeRet = expandContentModel(nodeRet, minOccurs, maxOccurs);
  218. }
  219. }
  220. return nodeRet;
  221. }
  222. // 2. expand all occurrence values: a{n, unbounded} -> a, a, ..., a+
  223. // a{n, m} -> a, a, ..., a?, a?, ...
  224. // 4. make sure each leaf node (XSCMLeaf) has a distinct position
  225. private CMNode expandContentModel(CMNode node,
  226. int minOccurs, int maxOccurs) {
  227. CMNode nodeRet = null;
  228. if (minOccurs==1 && maxOccurs==1) {
  229. nodeRet = node;
  230. }
  231. else if (minOccurs==0 && maxOccurs==1) {
  232. //zero or one
  233. nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, node);
  234. }
  235. else if (minOccurs == 0 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) {
  236. //zero or more
  237. nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_MORE, node);
  238. }
  239. else if (minOccurs == 1 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) {
  240. //one or more
  241. nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, node);
  242. }
  243. else if (maxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) {
  244. // => a,a,..,a+
  245. // create a+ node first, then put minOccurs-1 a's in front of it
  246. // for the first time "node" is used, we don't need to make a copy
  247. // and for other references to node, we make copies
  248. nodeRet = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ONE_OR_MORE, node);
  249. // (task 4) we need to call copyNode here, so that we append
  250. // an entire new copy of the node (a subtree). this is to ensure
  251. // all leaf nodes have distinct position
  252. // we know that minOccurs > 1
  253. nodeRet = fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE,
  254. multiNodes(node, minOccurs-1, true), nodeRet);
  255. }
  256. else {
  257. // {n,m} => a,a,a,...(a),(a),...
  258. // first n a's, then m-n a?'s.
  259. // copyNode is called, for the same reason as above
  260. if (minOccurs > 0) {
  261. nodeRet = multiNodes(node, minOccurs, false);
  262. }
  263. if (maxOccurs > minOccurs) {
  264. node = fNodeFactory.getCMUniOpNode(XSParticleDecl.PARTICLE_ZERO_OR_ONE, node);
  265. if (nodeRet == null) {
  266. nodeRet = multiNodes(node, maxOccurs-minOccurs, false);
  267. }
  268. else {
  269. nodeRet = fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE,
  270. nodeRet, multiNodes(node, maxOccurs-minOccurs, true));
  271. }
  272. }
  273. }
  274. return nodeRet;
  275. }
  276. private CMNode multiNodes(CMNode node, int num, boolean copyFirst) {
  277. if (num == 0) {
  278. return null;
  279. }
  280. if (num == 1) {
  281. return copyFirst ? copyNode(node) : node;
  282. }
  283. int num1 = num2;
  284. return fNodeFactory.getCMBinOpNode(XSModelGroupImpl.MODELGROUP_SEQUENCE,
  285. multiNodes(node, num1, copyFirst),
  286. multiNodes(node, num-num1, true));
  287. }
  288. // 4. make sure each leaf node (XSCMLeaf) has a distinct position
  289. private CMNode copyNode(CMNode node) {
  290. int type = node.type();
  291. // for choice or sequence, copy the two subtrees, and combine them
  292. if (type == XSModelGroupImpl.MODELGROUP_CHOICE ||
  293. type == XSModelGroupImpl.MODELGROUP_SEQUENCE) {
  294. XSCMBinOp bin = (XSCMBinOp)node;
  295. node = fNodeFactory.getCMBinOpNode(type, copyNode(bin.getLeft()),
  296. copyNode(bin.getRight()));
  297. }
  298. // for ?+*, copy the subtree, and put it in a new ?+* node
  299. else if (type == XSParticleDecl.PARTICLE_ZERO_OR_MORE ||
  300. type == XSParticleDecl.PARTICLE_ONE_OR_MORE ||
  301. type == XSParticleDecl.PARTICLE_ZERO_OR_ONE) {
  302. XSCMUniOp uni = (XSCMUniOp)node;
  303. node = fNodeFactory.getCMUniOpNode(type, copyNode(uni.getChild()));
  304. }
  305. // for element/wildcard (leaf), make a new leaf node,
  306. // with a distinct position
  307. else if (type == XSParticleDecl.PARTICLE_ELEMENT ||
  308. type == XSParticleDecl.PARTICLE_WILDCARD) {
  309. XSCMLeaf leaf = (XSCMLeaf)node;
  310. node = fNodeFactory.getCMLeafNode(leaf.type(), leaf.getLeaf(), leaf.getParticleId(), fLeafCount++);
  311. }
  312. return node;
  313. }
  314. }