001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.apache.xerces.dom;
059:
060: import org.w3c.dom.DocumentType;
061: import org.w3c.dom.EntityReference;
062: import org.w3c.dom.NamedNodeMap;
063: import org.w3c.dom.Node;
064: import org.w3c.dom.NodeList;
065:
066: /**
067: * EntityReference models the XML &entityname; syntax, when used for
068: * entities defined by the DOM. Entities hardcoded into XML, such as
069: * character entities, should instead have been translated into text
070: * by the code which generated the DOM tree.
071: * <P>
072: * An XML processor has the alternative of fully expanding Entities
073: * into the normal document tree. If it does so, no EntityReference nodes
074: * will appear.
075: * <P>
076: * Similarly, non-validating XML processors are not required to read
077: * or process entity declarations made in the external subset or
078: * declared in external parameter entities. Hence, some applications
079: * may not make the replacement value available for Parsed Entities
080: * of these types.
081: * <P>
082: * EntityReference behaves as a read-only node, and the children of
083: * the EntityReference (which reflect those of the Entity, and should
084: * also be read-only) give its replacement value, if any. They are
085: * supposed to automagically stay in synch if the DocumentType is
086: * updated with new values for the Entity.
087: * <P>
088: * The defined behavior makes efficient storage difficult for the DOM
089: * implementor. We can't just look aside to the Entity's definition
090: * in the DocumentType since those nodes have the wrong parent (unless
091: * we can come up with a clever "imaginary parent" mechanism). We
092: * must at least appear to clone those children... which raises the
093: * issue of keeping the reference synchronized with its parent.
094: * This leads me back to the "cached image of centrally defined data"
095: * solution, much as I dislike it.
096: * <P>
097: * For now I have decided, since REC-DOM-Level-1-19980818 doesn't
098: * cover this in much detail, that synchronization doesn't have to be
099: * considered while the user is deep in the tree. That is, if you're
100: * looking within one of the EntityReferennce's children and the Entity
101: * changes, you won't be informed; instead, you will continue to access
102: * the same object -- which may or may not still be part of the tree.
103: * This is the same behavior that obtains elsewhere in the DOM if the
104: * subtree you're looking at is deleted from its parent, so it's
105: * acceptable here. (If it really bothers folks, we could set things
106: * up so deleted subtrees are walked and marked invalid, but that's
107: * not part of the DOM's defined behavior.)
108: * <P>
109: * As a result, only the EntityReference itself has to be aware of
110: * changes in the Entity. And it can take advantage of the same
111: * structure-change-monitoring code I implemented to support
112: * DeepNodeList.
113: *
114: * @author Arnaud Le Hors, IBM
115: * @author Joe Kesselman, IBM
116: * @author Andy Clark, IBM
117: * @author Ralf Pfeiffer, IBM
118: * @version
119: * @since PR-DOM-Level-1-19980818.
120: */
121: public class EntityReferenceImpl extends ParentNode implements
122: EntityReference {
123:
124: //
125: // Constants
126: //
127:
128: /** Serialization version. */
129: static final long serialVersionUID = -7381452955687102062L;
130:
131: //
132: // Data
133: //
134:
135: /** Name of Entity referenced */
136: protected String name;
137:
138: /** Entity changes. */
139: //protected int entityChanges = -1;
140: /** Enable synchronize. */
141: //protected boolean fEnableSynchronize = false;
142: //
143: // Constructors
144: //
145: /** Factory constructor. */
146: public EntityReferenceImpl(CoreDocumentImpl ownerDoc, String name) {
147: super (ownerDoc);
148: this .name = name;
149: isReadOnly(true);
150: }
151:
152: //
153: // Node methods
154: //
155:
156: /**
157: * A short integer indicating what type of node this is. The named
158: * constants for this value are defined in the org.w3c.dom.Node interface.
159: */
160: public short getNodeType() {
161: return Node.ENTITY_REFERENCE_NODE;
162: }
163:
164: /**
165: * Returns the name of the entity referenced
166: */
167: public String getNodeName() {
168: if (needsSyncData()) {
169: synchronizeData();
170: }
171: return name;
172: }
173:
174: // REVISIT: Return original entity reference code. -Ac
175:
176: /**
177: * Perform synchronize() before accessing children.
178: *
179: * @return org.w3c.dom.NodeList
180: */
181: public NodeList getChildNodes() {
182: synchronize();
183: return super .getChildNodes();
184: }
185:
186: /**
187: * Perform synchronize() before accessing children.
188: *
189: * @return org.w3c.dom.NodeList
190: */
191: public Node getFirstChild() {
192: synchronize();
193: return super .getFirstChild();
194: }
195:
196: /**
197: * Perform synchronize() before accessing children.
198: *
199: * @return org.w3c.dom.NodeList
200: */
201: public Node getLastChild() {
202: synchronize();
203: return super .getLastChild();
204: }
205:
206: /**
207: * Query the number of children in the entity definition.
208: * (A bit more work than asking locally, but may be able to avoid
209: * or defer building the clone subtree.)
210: *
211: * @return org.w3c.dom.NodeList
212: */
213: public int getLength() {
214: synchronize();
215: return super .getLength();
216: }
217:
218: /**
219: * Returns whether this node has any children.
220: * @return boolean
221: */
222: public boolean hasChildNodes() {
223: synchronize();
224: return super .hasChildNodes();
225: }
226:
227: /** Returns the node at the given index. */
228: public Node item(int index) {
229: synchronize();
230: return super .item(index);
231: }
232:
233: /**
234: * EntityReference's children are a reflection of those defined in the
235: * named Entity. This method creates them if they haven't been created yet.
236: * This doesn't really support editing the Entity though.
237: */
238: protected void synchronize() {
239: if (firstChild != null) {
240: return;
241: }
242: DocumentType doctype;
243: NamedNodeMap entities;
244: EntityImpl entDef;
245: if (null != (doctype = getOwnerDocument().getDoctype())
246: && null != (entities = doctype.getEntities())) {
247:
248: entDef = (EntityImpl) entities.getNamedItem(getNodeName());
249:
250: // No Entity by this name, stop here.
251: if (entDef == null)
252: return;
253:
254: // If entity's definition exists, clone its kids
255: isReadOnly(false);
256: for (Node defkid = entDef.getFirstChild(); defkid != null; defkid = defkid
257: .getNextSibling()) {
258: Node newkid = defkid.cloneNode(true);
259: insertBefore(newkid, null);
260: }
261: setReadOnly(true, true);
262: }
263: }
264:
265: /**
266: * Enable the synchronize method which may do cloning. This method is enabled
267: * when the parser is done with an EntityReference.
268: /***
269: // revisit: enable editing of Entity
270: public void enableSynchronize(boolean enableSynchronize) {
271: fEnableSynchronize= enableSynchronize;
272: }
273: /***/
274:
275: /**
276: * EntityReference's children are a reflection of those defined in the
277: * named Entity. This method updates them if the Entity is changed.
278: * <P>
279: * It is unclear what the least-cost resynch mechanism is.
280: * If we expect the kids to be shallow, and/or expect changes
281: * to the Entity contents to be rare, wiping them all out
282: * and recloning is simplest.
283: * <P>
284: * If we expect them to be deep,
285: * it might be better to first decide which kids (if any)
286: * persist, and keep the ones (if any) that are unchanged
287: * rather than doing all the work of cloning them again.
288: * But that latter gets into having to convolve the two child lists,
289: * insert new information in the right order (and possibly reorder
290: * the existing kids), and a few other complexities that I really
291: * don't want to deal with in this implementation.
292: * <P>
293: * Note that if we decide that we need to update the EntityReference's
294: * contents, we have to turn off the readOnly flag temporarily to do so.
295: * When we get around to adding multitasking support, this whole method
296: * should probably be an atomic operation.
297: *
298: * @see DocumentTypeImpl
299: * @see EntityImpl
300: */
301: // The Xerces parser invokes callbacks for startEnityReference
302: // the parsed value of the entity EACH TIME, so it is actually
303: // easier to create the nodes through the callbacks rather than
304: // clone the Entity.
305: /***
306: // revisit: enable editing of Entity
307: private void synchronize() {
308: if (!fEnableSynchronize) {
309: return;
310: }
311: DocumentType doctype;
312: NamedNodeMap entities;
313: EntityImpl entDef;
314: if (null != (doctype = getOwnerDocument().getDoctype()) &&
315: null != (entities = doctype.getEntities())) {
316:
317: entDef = (EntityImpl)entities.getNamedItem(getNodeName());
318:
319: // No Entity by this name. If we had a change count, reset it.
320: if(null==entDef)
321: entityChanges=-1;
322:
323: // If no kids availalble, wipe any pre-existing children.
324: // (See discussion above.)
325: // Note that we have to use the superclass to avoid recursion
326: // through Synchronize.
327: readOnly=false;
328: if(null==entDef || !entDef.hasChildNodes())
329: for(Node kid=super.getFirstChild();
330: kid!=null;
331: kid=super.getFirstChild())
332: removeChild(kid);
333:
334: // If entity's definition changed, clone its kids
335: // (See discussion above.)
336: if(null!=entDef && entDef.changes!=entityChanges) {
337: for(Node defkid=entDef.getFirstChild();
338: defkid!=null;
339: defkid=defkid.getNextSibling()) {
340:
341: NodeImpl newkid=(NodeImpl) defkid.cloneNode(true);
342: newkid.setReadOnly(true,true);
343: insertBefore(newkid,null);
344: }
345: entityChanges=entDef.changes;
346: }
347: readOnly=true;
348: }
349: }
350: /***/
351:
352: } // class EntityReferenceImpl
|