View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the "License"); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.document;
13  import java.io.IOException;
14  import java.util.Collection;
15  import java.util.EnumSet;
16  import java.util.concurrent.locks.ReentrantLock;
17  import javax.xml.XMLConstants;
18  import javax.xml.namespace.QName;
19  import org.w3c.dom.Attr;
20  import org.w3c.dom.DocumentFragment;
21  import org.w3c.dom.Element;
22  import org.w3c.dom.Node;
23  import org.w3c.dom.Text;
24  import sk.baka.ikslibs.DOMUtils;
25  import sk.baka.ikslibs.interval.DOMInterval;
26  import sk.baka.ikslibs.levelmapper.NodeListID;
27  import sk.baka.ikslibs.modify.DOMMutils;
28  import sk.baka.ikslibs.ptr.DOMPoint;
29  import sk.baka.ikslibs.ptr.DomPointer;
30  import sk.baka.ikslibs.ptr.DomPointerFactory;
31  import sk.baka.ikslibs.ptr.DomPointerFlag;
32  import sk.baka.ikslibs.ref.EntityManager;
33  import sk.baka.xml.gene.ExportException;
34  import sk.uniba.euromath.Const;
35  import sk.uniba.euromath.tools.StringTools;
36  /***
37   * <p>
38   * Serves for modifying document. Tracks changes in document, and makes them
39   * consistent with 'splitted' images of document. Accessible from out of
40   * document package. All functions work on DOM-level nodes. Thread safe.
41   * </p>
42   * <p>
43   * This class is unchecked - it allows to set given text or modify document
44   * structure even if the change violates the grammar rules. Caller should make
45   * sure that the document is valid before the transformation execution.
46   * </p>
47   * <p>
48   * WARNING: when modifying the document, then IDs pointing to nodes after node
49   * being modified can become invalid (may denote a wrong node) - this happens
50   * for example when the text/cdata/comment/pi node is deleted (for example, when
51   * <code>null</code> value is given to a <code>setText()</code> function).
52   * </p>
53   * @author Martin Vysny
54   */
55  public final class DocumentModifier {
56  	/***
57  	 * Document.
58  	 */
59  	private final DomCore doc;
60  	/***
61  	 * Collections containing all opened views.
62  	 */
63  	private final Collection< ? extends DocumentView> views;
64  	/***
65  	 * Listens to the events.
66  	 */
67  	private final DocumentListeners listeners;
68  	/***
69  	 * This lock is locked when some thread starts the document modification,
70  	 * and released when a thread finishes the modification. When the lock is
71  	 * released, the document is transformed if there are no more threads
72  	 * waiting for the modification.
73  	 */
74  	private final ReentrantLock currentModifierLock = new ReentrantLock();
75  	/***
76  	 * Constructs instance of document modifier.
77  	 * @param doc modifies this document.
78  	 * @param views collection of views, opened for this document. This table is
79  	 * managed, and modified, by XMLAccess, DocumentModifier class doesn't
80  	 * modify it.
81  	 * @param listeners listens for document modifications
82  	 */
83  	DocumentModifier(DomCore doc, Collection< ? extends DocumentView> views,
84  			DocumentListeners listeners) {
85  		super();
86  		this.doc = doc;
87  		this.views = views;
88  		this.listeners = listeners;
89  	}
90  	/***
91  	 * <p>
92  	 * Begins modification sequence. All modifications to document must be
93  	 * enclosed with <code>startModify() .. endModify()</code> sequence. In
94  	 * other words, modifying document when <code>isModifying()==false</code>
95  	 * will result in <code>IllegalStateException</code>.
96  	 * <code>startModify()</code> calls can be nested, i.e. it is possible to
97  	 * call <code>startModify()</code> when <code>isModifying()</code>, but
98  	 * every call to <code>startModify()</code> should be closed with
99  	 * <code>endModify()</code>, otherwise document won't be never
100 	 * transformed, and other threads will block forever.
101 	 * </p>
102 	 * <p>
103 	 * Two threads cannot modify one document concurrently. If one thread is
104 	 * currently modifying a document and second thread calls
105 	 * <code>startModify()</code>, the function will block until current
106 	 * thread finishes the modification.
107 	 * </p>
108 	 */
109 	public void startModify() {
110 		currentModifierLock.lock();
111 		// this thread granted the right to modify the document.
112 	}
113 	/***
114 	 * Ends modification of document. It may still be possible to edit document,
115 	 * when every call to startModify() wasn't yet accompanied by endModify()
116 	 * call. When last startModify() is closed by this call, transformation is
117 	 * performed.
118 	 * @throws ExportException when something goes wrong in the process of
119 	 * transformation.
120 	 */
121 	public void endModify() throws ExportException {
122 		ensureModify();
123 		final boolean hasWaitingModifiers = currentModifierLock
124 				.hasQueuedThreads();
125 		final boolean unlocksLastLock = currentModifierLock.getHoldCount() <= 1;
126 		// unlock the lock.
127 		currentModifierLock.unlock();
128 		// if more modifiers are waiting for the modification to start, quit
129 		// immediately and let another thread execute startModify and gain the
130 		// lock.
131 		if (hasWaitingModifiers)
132 			return;
133 		if (unlocksLastLock) {
134 			// if something changed then execute the transformation
135 			if (doc.getSplittedChanges().hasChanges()) {
136 				for (final DocumentView view : views) {
137 					try {
138 						view.export();
139 					} catch (IOException ex) {
140 						throw new ExportException("I/O error: " //$NON-NLS-1$
141 								+ ex.getLocalizedMessage(), ex);
142 					}
143 				}
144 				doc.getSplittedChanges().clear();
145 				listeners.documentWasTransformed();
146 			}
147 		}
148 	}
149 	/***
150 	 * Returns <code>true</code>, if document is being modified by caller
151 	 * thread.
152 	 * @return <code>true</code>, if document is being modified,
153 	 * <code>false</code> otherwise.
154 	 */
155 	public boolean isModifying() {
156 		return currentModifierLock.isHeldByCurrentThread();
157 	}
158 	/***
159 	 * Ensures that document is being modified by caller thread. If not,
160 	 * <code>IllegalStateException</code> is thrown.
161 	 */
162 	void ensureModify() {
163 		if (!isModifying())
164 			throw new IllegalStateException(
165 					"Document is not currently being modified by this thread."); //$NON-NLS-1$
166 	}
167 	/***
168 	 * Sets text, denoted by given id, to given value. It may be pi, comment or
169 	 * attribute node.
170 	 * @param id id of text node, that receives new value.
171 	 * @param value new text value. <code>null</code> value is equivalent to
172 	 * an empty string.
173 	 * @deprecated
174 	 */
175 	@Deprecated
176 	public void setText(String id, String value) {
177 		NodeListID list = doc.getIDManager().getNode(id);
178 		DOMMutils.setText(list, value);
179 	}
180 	/***
181 	 * Sets text of given node to given value. It may be pi, comment, attribute,
182 	 * text or cdata node only.
183 	 * @param node the text node, that receives new value.
184 	 * @param value new text value. <code>null</code> value is equivalent to
185 	 * an empty string.
186 	 */
187 	public void setText(Node node, String value) {
188 		checkReserved(node);
189 		DOMMutils.setText(node, value);
190 	}
191 	/***
192 	 * Splits the text/cdata node at the specified position. If pos is equal to
193 	 * zero or length of textual value of given text then nothing happens. The
194 	 * node denoted by given id is not moved, only its textual value is changed.
195 	 * @param id the id of the text/cdata node
196 	 * @param pos zero-based position where the text shall be splitted.
197 	 * @return a second half of the splitted node. It may be <code>null</code>
198 	 * when no splitting occured.
199 	 * @deprecated
200 	 */
201 	@Deprecated
202 	public Text splitText(String id, int pos) {
203 		NodeListID list = doc.getIDManager().getNode(id);
204 		return DOMMutils.splitText(list.getPointer(pos, true, true));
205 	}
206 	/***
207 	 * Splits the text/cdata node at the specified position. If pos is equal to
208 	 * zero or length of textual value of given text then nothing happens. The
209 	 * node denoted by given id is not moved, only its textual value is changed.
210 	 * @param text the text/cdata node
211 	 * @param pos zero-based position where the text shall be splitted.
212 	 * @return a second half of the splitted node. It may be <code>null</code>
213 	 * when no splitting occured.
214 	 * @deprecated
215 	 */
216 	@Deprecated
217 	public Text splitText(Text text, int pos) {
218 		return DOMMutils.splitText(text, pos);
219 	}
220 	/***
221 	 * Splits the text/cdata node at the specified position. If pos is equal to
222 	 * zero or length of textual value of given text then nothing happens. The
223 	 * node denoted by given id is not moved, only its textual value is changed.
224 	 * @param ptr the pointer pointing into the text/cdata node.
225 	 * @return a second half of the splitted node. It may be <code>null</code>
226 	 * when no splitting occured.
227 	 * @deprecated
228 	 */
229 	@Deprecated
230 	public Text splitText(DomPointer ptr) {
231 		return DOMMutils.splitText(ptr);
232 	}
233 	/***
234 	 * Inserts text into element, depending on given parameters. If ip points
235 	 * into text, then that text is modified instead. If ip points to a location
236 	 * next to node with equal type, then that text is modified instead.
237 	 * @param ip insert point, where to insert new text.
238 	 * @param contextId the context element, where new text must be inserted.
239 	 * @param value new text value. if <code>null</code> or empty string ("")
240 	 * is given, then nothing is created.
241 	 * @param type type of created node, one of <code>Node.TEXT_NODE</code> or
242 	 * <code>Node.CDATA_SECTION_NODE</code> constants. When modifying text,
243 	 * this parameter is ignored.
244 	 * @return id of newly created text element, or id of modified element. If
245 	 * value is empty or null, then <code>null</code> is returned.
246 	 * @throws DocumentException when element with given id doesn't exist or it
247 	 * doesn't denote regular element.
248 	 * @deprecated
249 	 */
250 	@Deprecated
251 	public String insertText(DOMPoint ip, String contextId, String value,
252 			short type) throws DocumentException {
253 		return insertText(ip, doc.getContent().getElement(contextId), value,
254 				type);
255 	}
256 	/***
257 	 * Inserts text into element, depending on given parameters. If ip points
258 	 * into text, then that text is modified instead. If ip points to a location
259 	 * next to node with equal type, then that text is modified instead.
260 	 * @param point insert point, where to insert new text. It must not point
261 	 * into an entity.
262 	 * @param value new text value. if <code>null</code> or empty string ("")
263 	 * is given, then nothing is created.
264 	 * @param type type of created node, one of <code>Node.TEXT_NODE</code> or
265 	 * <code>Node.CDATA_SECTION_NODE</code> constants. When modifying text,
266 	 * this parameter is ignored.
267 	 * @return id of newly created text element, or id of modified element. If
268 	 * value is empty or null, then <code>null</code> is returned.
269 	 * @deprecated
270 	 */
271 	@Deprecated
272 	public String insertText(final DomPointer point, final String value,
273 			short type) {
274 		final Node n= DOMMutils.insertText(point, value, type);
275 		if(n==null)return null;
276 		return doc.getIDManager().getID(n);
277 	}
278 	/***
279 	 * Inserts text into element, depending on given parameters. If ip points
280 	 * into text, then that text is modified instead. If ip points to a location
281 	 * next to node with equal type, then that text is modified instead.
282 	 * @param ip insert point, where to insert new text.
283 	 * @param contextElement the context element, where new text must be
284 	 * inserted.
285 	 * @param value new text value. if <code>null</code> or empty string ("")
286 	 * is given, then nothing is created.
287 	 * @param type type of created node, one of <code>Node.TEXT_NODE</code> or
288 	 * <code>Node.CDATA_SECTION_NODE</code> constants. When modifying text,
289 	 * this parameter is ignored.
290 	 * @return id of newly created text element, or id of modified element. If
291 	 * value is empty or null, then <code>null</code> is returned.
292 	 * @deprecated
293 	 */
294 	@Deprecated
295 	public String insertText(DOMPoint ip, Element contextElement,
296 			String value, short type) {
297 		final Node n= DOMMutils.insertText(ip, contextElement, value, type);
298 		if(n==null)return null;
299 		return doc.getIDManager().getID(n);
300 	}
301 	/***
302 	 * Removes node(s) with given id from document.
303 	 * @param id id of the node, that will be removed.
304 	 * @deprecated
305 	 */
306 	@Deprecated
307 	public void remove(String id) {
308 		final NodeListID list = doc.getIDManager().getNode(id);
309 		if (!list.isTextual()) {
310 			// non-textual list can contain only single node. remove it normally
311 			remove(list.item(0));
312 			return;
313 		}
314 		// try to remove the textual list
315 		remove(list.getStart(), list.getEnd());
316 	}
317 	/***
318 	 * Removes given node from the document. If both previous and next sibling
319 	 * of the node are of same text type (text or cdata) then these nodes are
320 	 * merged into one.
321 	 * @param node the node, that will be removed. Its id is removed aswell, but
322 	 * the id of descendants is not removed.
323 	 */
324 	public void remove(Node node) {
325 		checkReserved(node);
326 		DOMMutils.remove(node);
327 	}
328 	/***
329 	 * Check if such node is reserved and cannot be created in the document.
330 	 * @param node node to check.
331 	 * @throws IllegalArgumentException if node is reserved.
332 	 */
333 	private void checkReserved(final Node node) {
334 		checkReserved(node.getNamespaceURI(), node.getNodeType());
335 	}
336 	/***
337 	 * Check if such node is reserved and cannot be created in the document.
338 	 * @param namespace the namespace of the node
339 	 * @param nodeType the type of the node.
340 	 * @throws IllegalArgumentException if node is reserved.
341 	 */
342 	private void checkReserved(final String namespace, final short nodeType) {
343 		if ((nodeType != Node.ATTRIBUTE_NODE)
344 				&& (nodeType != Node.ELEMENT_NODE))
345 			return;
346 		if (StringTools.nonNullStr(namespace).startsWith(Const.EM_URI))
347 			throw new IllegalArgumentException(
348 					"Namespace " + Const.EM_URI + " is reserved."); //$NON-NLS-1$ //$NON-NLS-2$
349 	}
350 	/***
351 	 * Creates an attribute. If attribute with given local name and namespace is
352 	 * already present in context node, its value is modified instead - prefix
353 	 * is not changed.
354 	 * @param id id of element, that contains the attribute.
355 	 * @param prefix prefix of qname of attribute. See
356 	 * <code>NamespaceManager</code> for details.
357 	 * @param localName local name of attribute.
358 	 * @param namespace namespace of attribute.
359 	 * @param value new value for attribute.
360 	 * @return ID of newly created attribute.
361 	 */
362 	public String createAttribute(String id, String prefix, String localName,
363 			String namespace, String value) {
364 		return createAttribute(doc.getIDManager().getElement(id), prefix,
365 				localName, namespace, value);
366 	}
367 	/***
368 	 * Creates an attribute. If attribute with given local name and namespace is
369 	 * already present in context node, its value is modified instead - prefix
370 	 * is not changed.
371 	 * @param id id of element, that contains the attribute.
372 	 * @param qname qualified name of the attribute
373 	 * @param value new value for attribute.
374 	 * @return ID of newly created attribute.
375 	 */
376 	public String createAttribute(String id, QName qname, String value)
377 			{
378 		return createAttribute(id, qname.getPrefix(), qname.getLocalPart(),
379 				qname.getNamespaceURI(), value);
380 	}
381 	/***
382 	 * Creates an attribute. If attribute with given local name and namespace is
383 	 * already present in context node, its value is modified instead - prefix
384 	 * is not changed.
385 	 * @param e element, that contains the attribute.
386 	 * @param qname qualified name of the attribute
387 	 * @param value new value for attribute.
388 	 * @return ID of newly created attribute.
389 	 */
390 	public String createAttribute(Element e, QName qname, String value) {
391 		return createAttribute(e, qname.getPrefix(), qname.getLocalPart(),
392 				qname.getNamespaceURI(), value);
393 	}
394 	/***
395 	 * Creates an attribute. If attribute with given local name and namespace is
396 	 * already present in context node, its value is modified instead - prefix
397 	 * is not changed.
398 	 * @param e element, that contains the attribute.
399 	 * @param prefix prefix of qname of attribute. See
400 	 * <code>NamespaceManager</code> for details.
401 	 * @param localName local name of attribute.
402 	 * @param namespace namespace of attribute.
403 	 * @param value new value for attribute.
404 	 * @return ID of newly created attribute.
405 	 */
406 	public String createAttribute(Element e, String prefix, String localName,
407 			String namespace, String value) {
408 		// forbid creating reserved attribute
409 		checkReserved(namespace, Node.ATTRIBUTE_NODE);
410 		// if namespace is equal to namespace of parent element, then null it.
411 		if (DOMUtils.equalsURI(namespace, e.getNamespaceURI())) {
412 			namespace = XMLConstants.NULL_NS_URI;
413 			prefix = XMLConstants.DEFAULT_NS_PREFIX;
414 		}
415 		final Attr attr=DOMMutils.createAttribute(e, prefix, localName, namespace, value);
416 		return doc.getIDManager().getID(attr);
417 	}
418 	/***
419 	 * Inserts the node at the specified pointer. The function does not use the
420 	 * ip part of the pointer hence it inserts node into correct place even if
421 	 * there was a node already inserted before this place. IP part is used only
422 	 * if merge is true and the node is a text or cdata node. If the node is an
423 	 * element then it receives an id, however no descendant elements receives
424 	 * an id.
425 	 * @param node the node to insert, it must be element, comment, pi, text or
426 	 * cdata only.
427 	 * @param ptr where to insert the node.
428 	 * @param merge if <code>true</code> then if new node is a text node then
429 	 * it will be merged with adjacent nodes if possible. If <code>false</code>
430 	 * then no merging is performed.
431 	 * @deprecated
432 	 */
433 	@Deprecated
434 	public void insertNode(Node node, DomPointer ptr, boolean merge) {
435 		DOMMutils.insertNode(node, ptr, merge);
436 	}
437 	/***
438 	 * Inserts all nodes from specified document fragment into specified
439 	 * position. All nodes are automatically merged. All <code>emp:id</code>
440 	 * attributes are ignored. All nodes are removed from the fragment in the
441 	 * process and become part of the document.
442 	 * @param frag the fragment
443 	 * @param ptr where to insert nodes from the fragment.
444 	 * @deprecated
445 	 */
446 	@Deprecated
447 	public void insertFragment(DocumentFragment frag, DomPointer ptr) {
448 		DOMMutils.insertFragment(frag, ptr);
449 	}
450 	/***
451 	 * Replaces the node with another node. <code>newNode</code> must have
452 	 * <code>null</code> parent or it must be from another document.
453 	 * @param node the node to be replaced.
454 	 * @param newNode the node will be replaced with this node. If
455 	 * <code>null</code> then given node is removed. If not from our document
456 	 * then it is automatically imported.
457 	 */
458 	public void replaceNode(Node node, Node newNode) {
459 		if (newNode == null) {
460 			remove(node);
461 			return;
462 		}
463 		doc.checkNode(node);
464 		if ((newNode.getParentNode() != null) && (doc.isOurNode(newNode)))
465 			throw new IllegalArgumentException(
466 					"The replacing node is present in our document"); //$NON-NLS-1$
467 		ensureModify();
468 		// remove old node from the document
469 		final Node nextSibling = node.getNextSibling();
470 		final Node parent = node.getParentNode();
471 		parent.removeChild(node);
472 		// insert new node into its place
473 		Node replaceBy = newNode;
474 		if (!doc.isOurNode(replaceBy))
475 			replaceBy = doc.getDocument().importNode(newNode, true);
476 		DOMMutils.insertNode(replaceBy, DomPointerFactory.create(nextSibling), true);
477 	}
478 	/***
479 	 * Checks whether all nodes from specified range can be deleted - i.e. if
480 	 * <code>delete</code> with these parameters shall succeed.
481 	 * @param from start of the removal interval. The node where this pointer
482 	 * points shall be removed (an exception is if some contents of the node are
483 	 * left after the operation).
484 	 * @param to end of the removal interval.
485 	 * @return <code>true</code> if the specified interval is removable,
486 	 * <code>false</code> otherwise.
487 	 */
488 	public boolean isRemovable(DomPointer from, DomPointer to) {
489 		// TODO MaVy p0> unify with DOMInterval.isDeletable()
490 		// try to skip from entities
491 		// 'to' can be null - in such case it points at the end of the document.
492 		if (to != null)
493 			to = to.getNext(EnumSet.of(DomPointerFlag.NotIntoEntity,
494 					DomPointerFlag.PointToNode), true, false,false);
495 		if (to != null)
496 			to = to.skipFromEntities();
497 		if (to == null)
498 			to = DomPointerFactory.getLast(doc.getDocument(),
499 					EnumSet.of(DomPointerFlag.NotIntoEntity));
500 		// if we are now pointing into an entity then it is somewhere in middle
501 		// of the entity -> cannot remove.
502 		if (to.inEntity())
503 			return false;
504 		// find first node - any node will do
505 		from = from.getNext(EnumSet.of(DomPointerFlag.NotIntoEntity,
506 				DomPointerFlag.PointToNode), true, false,false);
507 		if (from != null)
508 			to = to.skipFromEntities();
509 		if (from == null) {
510 			// nothing to do, from points at the end of the document, nothing
511 			// can be removed, just quit.
512 			return true;
513 		}
514 		// if we are now pointing into an entity then it is somewhere in middle
515 		// of the entity -> cannot remove.
516 		if (from.inEntity())
517 			return false;
518 		if (from.equals(to))
519 			return true;
520 		if (from.compareTo(to) > 0)
521 			throw new IllegalArgumentException("'from' must be less than 'to'"); //$NON-NLS-1$
522 		return true;
523 	}
524 	/***
525 	 * Tries to remove all nodes in the specified range (the node pointed to by
526 	 * <code>to</code> parameter is not removed). The function shall not
527 	 * remove elements that shall not have all its children removed.
528 	 * @param from start of the removal interval. The node where this pointer
529 	 * points shall be removed (exception is a node which have some children
530 	 * left after the operation).
531 	 * @param to end of the removal interval. It may be <code>null</code>- in
532 	 * such case the function shall remove all nodes to the end of the document.
533 	 * @deprecated
534 	 */
535 	@Deprecated
536 	public void remove(DomPointer from, DomPointer to) {
537 		new DOMInterval(from,to).toRange().deleteContents();
538 	}
539 	/***
540 	 * Tries to remove all nodes in the specified range (the node pointed to by
541 	 * <code>to</code> parameter is not removed). Removed nodes are returned
542 	 * in a <code>DocumentFragment</code> instance. Both pointers must have
543 	 * the same parent element.
544 	 * @param from start of the removal interval. The node where this pointer
545 	 * points shall be removed.
546 	 * @param to end of the removal interval.
547 	 * @return <code>DocumentFragment</code> instance containing nodes that
548 	 * have been cut from the document. Never <code>null</code>. No element
549 	 * in the target fragment will have <code>emp:id</code> attribute.
550 	 * @deprecated
551 	 */
552 	@Deprecated
553 	public DocumentFragment cut(DomPointer from, DomPointer to) {
554 		return new DOMInterval(from,to).toRange().extractContents();
555 	}
556 	/***
557 	 * Tries to insert some text into specified position.
558 	 * @param list current list of nodes, where to insert the text.
559 	 * @param pos the position in the <code>textValue</code> string.
560 	 * @param type type of created node, one of <code>Node.TEXT_NODE</code> or
561 	 * <code>Node.CDATA_SECTION_NODE</code> constants. When modifying text,
562 	 * this parameter is ignored.
563 	 * @param text the text to be inserted
564 	 * @return new instance of list that reflects the changes made to the
565 	 * document.
566 	 * @throws IllegalArgumentException if no text can be inserted at specified
567 	 * position.
568 	 * @deprecated
569 	 */
570 	@Deprecated
571 	public NodeListID insertText(NodeListID list, int pos, String text,
572 			short type) {
573 		DOMMutils.insertText(list, pos, text, type);
574 		NodeListID result = list.recover();
575 		return result;
576 	}
577 	/***
578 	 * Inserts an entity into specified position.
579 	 * @param list current list of nodes, where to insert the entity.
580 	 * @param pos the position in the <code>textValue</code> string.
581 	 * @param entityName the name of the entity.
582 	 * @return new instance of list that reflects the changes made to the
583 	 * document.
584 	 * @deprecated
585 	 */
586 	@Deprecated
587 	public NodeListID insertEntity(NodeListID list, int pos, String entityName) {
588 		final EntityManager em = doc.getEntityManager();
589 		DOMMutils.insertEntity(list, pos, entityName, em);
590 		final NodeListID result = list.recover();
591 		return result;
592 	}
593 	/***
594 	 * Tries to delete specified range of text.
595 	 * @param list list of text/cdata nodes. If function finishes succesfully
596 	 * and the document gets modified, this list is invalid and must not be
597 	 * used.
598 	 * @param fromPos the starting position
599 	 * @param toPos the ending position - character at this position shall not
600 	 * be deleted.
601 	 * @return new instance of list that reflects the changes made to the
602 	 * document.
603 	 * @deprecated
604 	 */
605 	@Deprecated
606 	public NodeListID delete(NodeListID list, int fromPos, int toPos) {
607 		DOMMutils.delete(list, fromPos, toPos);
608 		final NodeListID result = list.recover();
609 		return result;
610 	}
611 }