1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2002 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.dom;
  58. import org.w3c.dom.DocumentType;
  59. import org.w3c.dom.EntityReference;
  60. import org.w3c.dom.NamedNodeMap;
  61. import org.w3c.dom.Node;
  62. /**
  63. * EntityReference models the XML &entityname; syntax, when used for
  64. * entities defined by the DOM. Entities hardcoded into XML, such as
  65. * character entities, should instead have been translated into text
  66. * by the code which generated the DOM tree.
  67. * <P>
  68. * An XML processor has the alternative of fully expanding Entities
  69. * into the normal document tree. If it does so, no EntityReference nodes
  70. * will appear.
  71. * <P>
  72. * Similarly, non-validating XML processors are not required to read
  73. * or process entity declarations made in the external subset or
  74. * declared in external parameter entities. Hence, some applications
  75. * may not make the replacement value available for Parsed Entities
  76. * of these types.
  77. * <P>
  78. * EntityReference behaves as a read-only node, and the children of
  79. * the EntityReference (which reflect those of the Entity, and should
  80. * also be read-only) give its replacement value, if any. They are
  81. * supposed to automagically stay in synch if the DocumentType is
  82. * updated with new values for the Entity.
  83. * <P>
  84. * The defined behavior makes efficient storage difficult for the DOM
  85. * implementor. We can't just look aside to the Entity's definition
  86. * in the DocumentType since those nodes have the wrong parent (unless
  87. * we can come up with a clever "imaginary parent" mechanism). We
  88. * must at least appear to clone those children... which raises the
  89. * issue of keeping the reference synchronized with its parent.
  90. * This leads me back to the "cached image of centrally defined data"
  91. * solution, much as I dislike it.
  92. * <P>
  93. * For now I have decided, since REC-DOM-Level-1-19980818 doesn't
  94. * cover this in much detail, that synchronization doesn't have to be
  95. * considered while the user is deep in the tree. That is, if you're
  96. * looking within one of the EntityReferennce's children and the Entity
  97. * changes, you won't be informed; instead, you will continue to access
  98. * the same object -- which may or may not still be part of the tree.
  99. * This is the same behavior that obtains elsewhere in the DOM if the
  100. * subtree you're looking at is deleted from its parent, so it's
  101. * acceptable here. (If it really bothers folks, we could set things
  102. * up so deleted subtrees are walked and marked invalid, but that's
  103. * not part of the DOM's defined behavior.)
  104. * <P>
  105. * As a result, only the EntityReference itself has to be aware of
  106. * changes in the Entity. And it can take advantage of the same
  107. * structure-change-monitoring code I implemented to support
  108. * DeepNodeList.
  109. *
  110. * @author Arnaud Le Hors, IBM
  111. * @author Joe Kesselman, IBM
  112. * @author Andy Clark, IBM
  113. * @author Ralf Pfeiffer, IBM
  114. * @version $Id: EntityReferenceImpl.java,v 1.23 2003/05/08 19:52:40 elena Exp $
  115. * @since PR-DOM-Level-1-19980818.
  116. */
  117. public class EntityReferenceImpl
  118. extends ParentNode
  119. implements EntityReference {
  120. //
  121. // Constants
  122. //
  123. /** Serialization version. */
  124. static final long serialVersionUID = -7381452955687102062L;
  125. //
  126. // Data
  127. //
  128. /** Name of Entity referenced */
  129. protected String name;
  130. /** Base URI*/
  131. protected String baseURI;
  132. /** Entity changes. */
  133. //protected int entityChanges = -1;
  134. /** Enable synchronize. */
  135. //protected boolean fEnableSynchronize = false;
  136. //
  137. // Constructors
  138. //
  139. /** Factory constructor. */
  140. public EntityReferenceImpl(CoreDocumentImpl ownerDoc, String name) {
  141. super(ownerDoc);
  142. this.name = name;
  143. isReadOnly(true);
  144. needsSyncChildren(true);
  145. }
  146. //
  147. // Node methods
  148. //
  149. /**
  150. * A short integer indicating what type of node this is. The named
  151. * constants for this value are defined in the org.w3c.dom.Node interface.
  152. */
  153. public short getNodeType() {
  154. return Node.ENTITY_REFERENCE_NODE;
  155. }
  156. /**
  157. * Returns the name of the entity referenced
  158. */
  159. public String getNodeName() {
  160. if (needsSyncData()) {
  161. synchronizeData();
  162. }
  163. return name;
  164. }
  165. /** Clone node. */
  166. public Node cloneNode(boolean deep) {
  167. EntityReferenceImpl er = (EntityReferenceImpl)super.cloneNode(deep);
  168. er.setReadOnly(true, deep);
  169. return er;
  170. }
  171. /**
  172. * DOM Level 3 WD - Experimental.
  173. * Retrieve baseURI
  174. */
  175. public String getBaseURI() {
  176. if (needsSyncData()) {
  177. synchronizeData();
  178. }
  179. if (baseURI == null) {
  180. DocumentType doctype;
  181. NamedNodeMap entities;
  182. EntityImpl entDef;
  183. if (null != (doctype = getOwnerDocument().getDoctype()) &&
  184. null != (entities = doctype.getEntities())) {
  185. entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  186. if (entDef !=null) {
  187. return entDef.getBaseURI();
  188. }
  189. }
  190. }
  191. return baseURI;
  192. }
  193. /** NON-DOM: set base uri*/
  194. public void setBaseURI(String uri){
  195. if (needsSyncData()) {
  196. synchronizeData();
  197. }
  198. baseURI = uri;
  199. }
  200. /**
  201. * NON-DOM: compute string representation of the entity reference.
  202. * This method is used to retrieve a string value for an attribute node that has child nodes.
  203. * @return String representing a value of this entity ref. or
  204. * null if any node other than EntityReference, Text is encountered
  205. * during computation
  206. */
  207. protected String getEntityRefValue (){
  208. if (needsSyncChildren()){
  209. synchronizeChildren();
  210. }
  211. String value = "";
  212. if (firstChild != null){
  213. if (firstChild.getNodeType() == Node.ENTITY_REFERENCE_NODE){
  214. value = ((EntityReferenceImpl)firstChild).getEntityRefValue();
  215. }
  216. else if (firstChild.getNodeType() == Node.TEXT_NODE){
  217. value = firstChild.getNodeValue();
  218. }
  219. else {
  220. // invalid to have other types of nodes in attr value
  221. return null;
  222. }
  223. if (firstChild.nextSibling == null){
  224. return value;
  225. }
  226. else {
  227. StringBuffer buff = new StringBuffer(value);
  228. ChildNode next = firstChild.nextSibling;
  229. while (next != null){
  230. if (next.getNodeType() == Node.ENTITY_REFERENCE_NODE){
  231. value = ((EntityReferenceImpl)next).getEntityRefValue();
  232. }
  233. else if (next.getNodeType() == Node.TEXT_NODE){
  234. value = next.getNodeValue();
  235. }
  236. else {
  237. // invalid to have other types of nodes in attr value
  238. return null;
  239. }
  240. buff.append(value);
  241. next = next.nextSibling;
  242. }
  243. return buff.toString();
  244. }
  245. }
  246. return "";
  247. }
  248. /**
  249. * EntityReference's children are a reflection of those defined in the
  250. * named Entity. This method creates them if they haven't been created yet.
  251. * This doesn't support editing the Entity though, since this only called
  252. * once for all.
  253. */
  254. protected void synchronizeChildren() {
  255. // no need to synchronize again
  256. needsSyncChildren(false);
  257. DocumentType doctype;
  258. NamedNodeMap entities;
  259. EntityImpl entDef;
  260. if (null != (doctype = getOwnerDocument().getDoctype()) &&
  261. null != (entities = doctype.getEntities())) {
  262. entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  263. // No Entity by this name, stop here.
  264. if (entDef == null)
  265. return;
  266. // If entity's definition exists, clone its kids
  267. isReadOnly(false);
  268. for (Node defkid = entDef.getFirstChild();
  269. defkid != null;
  270. defkid = defkid.getNextSibling()) {
  271. Node newkid = defkid.cloneNode(true);
  272. insertBefore(newkid, null);
  273. }
  274. setReadOnly(true, true);
  275. }
  276. }
  277. /**
  278. * NON-DOM: sets the node and its children value.
  279. * <P>
  280. * Note: make sure that entity reference and its kids could be set readonly.
  281. */
  282. public void setReadOnly(boolean readOnly, boolean deep) {
  283. if (needsSyncData()) {
  284. synchronizeData();
  285. }
  286. if (deep) {
  287. if (needsSyncChildren()) {
  288. synchronizeChildren();
  289. }
  290. // Recursively set kids
  291. for (ChildNode mykid = firstChild;
  292. mykid != null;
  293. mykid = mykid.nextSibling) {
  294. mykid.setReadOnly(readOnly,true);
  295. }
  296. }
  297. isReadOnly(readOnly);
  298. } // setReadOnly(boolean,boolean)
  299. /**
  300. * Enable the synchronize method which may do cloning. This method is enabled
  301. * when the parser is done with an EntityReference.
  302. /***
  303. // revisit: enable editing of Entity
  304. public void enableSynchronize(boolean enableSynchronize) {
  305. fEnableSynchronize= enableSynchronize;
  306. }
  307. /***/
  308. /**
  309. * EntityReference's children are a reflection of those defined in the
  310. * named Entity. This method updates them if the Entity is changed.
  311. * <P>
  312. * It is unclear what the least-cost resynch mechanism is.
  313. * If we expect the kids to be shallow, and/or expect changes
  314. * to the Entity contents to be rare, wiping them all out
  315. * and recloning is simplest.
  316. * <P>
  317. * If we expect them to be deep,
  318. * it might be better to first decide which kids (if any)
  319. * persist, and keep the ones (if any) that are unchanged
  320. * rather than doing all the work of cloning them again.
  321. * But that latter gets into having to convolve the two child lists,
  322. * insert new information in the right order (and possibly reorder
  323. * the existing kids), and a few other complexities that I really
  324. * don't want to deal with in this implementation.
  325. * <P>
  326. * Note that if we decide that we need to update the EntityReference's
  327. * contents, we have to turn off the readOnly flag temporarily to do so.
  328. * When we get around to adding multitasking support, this whole method
  329. * should probably be an atomic operation.
  330. *
  331. * @see DocumentTypeImpl
  332. * @see EntityImpl
  333. */
  334. // The Xerces parser invokes callbacks for startEnityReference
  335. // the parsed value of the entity EACH TIME, so it is actually
  336. // easier to create the nodes through the callbacks rather than
  337. // clone the Entity.
  338. /***
  339. // revisit: enable editing of Entity
  340. private void synchronize() {
  341. if (!fEnableSynchronize) {
  342. return;
  343. }
  344. DocumentType doctype;
  345. NamedNodeMap entities;
  346. EntityImpl entDef;
  347. if (null != (doctype = getOwnerDocument().getDoctype()) &&
  348. null != (entities = doctype.getEntities())) {
  349. entDef = (EntityImpl)entities.getNamedItem(getNodeName());
  350. // No Entity by this name. If we had a change count, reset it.
  351. if(null==entDef)
  352. entityChanges=-1;
  353. // If no kids availalble, wipe any pre-existing children.
  354. // (See discussion above.)
  355. // Note that we have to use the superclass to avoid recursion
  356. // through Synchronize.
  357. readOnly=false;
  358. if(null==entDef || !entDef.hasChildNodes())
  359. for(Node kid=super.getFirstChild();
  360. kid!=null;
  361. kid=super.getFirstChild())
  362. removeChild(kid);
  363. // If entity's definition changed, clone its kids
  364. // (See discussion above.)
  365. if(null!=entDef && entDef.changes!=entityChanges) {
  366. for(Node defkid=entDef.getFirstChild();
  367. defkid!=null;
  368. defkid=defkid.getNextSibling()) {
  369. NodeImpl newkid=(NodeImpl) defkid.cloneNode(true);
  370. newkid.setReadOnly(true,true);
  371. insertBefore(newkid,null);
  372. }
  373. entityChanges=entDef.changes;
  374. }
  375. readOnly=true;
  376. }
  377. }
  378. /***/
  379. } // class EntityReferenceImpl