KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > dom > CharacterDataImpl


1 /*
2  * Copyright 1999-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.dom;
18
19 import org.w3c.dom.DOMException JavaDoc;
20 import org.w3c.dom.Node JavaDoc;
21 import org.w3c.dom.NodeList JavaDoc;
22
23 /**
24  * CharacterData is an abstract Node that can carry character data as its
25  * Value. It provides shared behavior for Text, CData, and
26  * possibly other node types. All offsets are 0-based.
27  * <p>
28  * Since ProcessingInstructionImpl inherits from this class to reuse the
29  * setNodeValue method, this class isn't declared as implementing the interface
30  * CharacterData. This is done by relevant subclasses (TexImpl, CommentImpl).
31  * <p>
32  * This class doesn't directly support mutation events, however, it notifies
33  * the document when mutations are performed so that the document class do so.
34  *
35  * @xerces.internal
36  *
37  * @version $Id: CharacterDataImpl.java,v 1.24 2004/11/04 20:42:20 mrglavas Exp $
38  * @since PR-DOM-Level-1-19980818.
39  */

40 public abstract class CharacterDataImpl
41     extends ChildNode {
42
43     //
44
// Constants
45
//
46

47     /** Serialization version. */
48     static final long serialVersionUID = 7931170150428474230L;
49
50     //
51
// Data
52
//
53

54     protected String JavaDoc data;
55
56     /** Empty child nodes. */
57     private static transient NodeList JavaDoc singletonNodeList = new NodeList JavaDoc() {
58         public Node JavaDoc item(int index) { return null; }
59         public int getLength() { return 0; }
60     };
61
62     //
63
// Constructors
64
//
65

66     public CharacterDataImpl(){}
67
68     /** Factory constructor. */
69     protected CharacterDataImpl(CoreDocumentImpl ownerDocument, String JavaDoc data) {
70         super(ownerDocument);
71         this.data = data;
72     }
73
74     //
75
// Node methods
76
//
77

78     /** Returns an empty node list. */
79     public NodeList JavaDoc getChildNodes() {
80         return singletonNodeList;
81     }
82
83     /*
84      * returns the content of this node
85      */

86     public String JavaDoc getNodeValue() {
87         if (needsSyncData()) {
88             synchronizeData();
89         }
90         return data;
91     }
92
93    /** Convenience wrapper for calling setNodeValueInternal when
94      * we are not performing a replacement operation
95      */

96     protected void setNodeValueInternal (String JavaDoc value) {
97         setNodeValueInternal(value, false);
98     }
99     
100     /** This function added so that we can distinguish whether
101      * setNodeValue has been called from some other DOM functions.
102      * or by the client.<p>
103      * This is important, because we do one type of Range fix-up,
104      * from the high-level functions in CharacterData, and another
105      * type if the client simply calls setNodeValue(value).
106      */

107     protected void setNodeValueInternal(String JavaDoc value, boolean replace) {
108         
109         CoreDocumentImpl ownerDocument = ownerDocument();
110         
111         if (ownerDocument.errorChecking && isReadOnly()) {
112             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
113             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
114         }
115         
116         // revisit: may want to set the value in ownerDocument.
117
// Default behavior, overridden in some subclasses
118
if (needsSyncData()) {
119             synchronizeData();
120         }
121         
122         // keep old value for document notification
123
String JavaDoc oldvalue = this.data;
124         
125         // notify document
126
ownerDocument.modifyingCharacterData(this, replace);
127         
128         this.data = value;
129         
130         // notify document
131
ownerDocument.modifiedCharacterData(this, oldvalue, value, replace);
132     }
133
134     /**
135      * Sets the content, possibly firing related events,
136      * and updating ranges (via notification to the document)
137      */

138     public void setNodeValue(String JavaDoc value) {
139
140         setNodeValueInternal(value);
141
142         // notify document
143
ownerDocument().replacedText(this);
144     }
145
146     //
147
// CharacterData methods
148
//
149

150     /**
151      * Retrieve character data currently stored in this node.
152      *
153      * @throws DOMExcpetion(DOMSTRING_SIZE_ERR) In some implementations,
154      * the stored data may exceed the permitted length of strings. If so,
155      * getData() will throw this DOMException advising the user to
156      * instead retrieve the data in chunks via the substring() operation.
157      */

158     public String JavaDoc getData() {
159         if (needsSyncData()) {
160             synchronizeData();
161         }
162         return data;
163     }
164
165     /**
166      * Report number of characters currently stored in this node's
167      * data. It may be 0, meaning that the value is an empty string.
168      */

169     public int getLength() {
170         if (needsSyncData()) {
171             synchronizeData();
172         }
173         return data.length();
174     }
175
176     /**
177      * Concatenate additional characters onto the end of the data
178      * stored in this node. Note that this, and insert(), are the paths
179      * by which a DOM could wind up accumulating more data than the
180      * language's strings can easily handle. (See above discussion.)
181      *
182      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
183      */

184     public void appendData(String JavaDoc data) {
185
186         if (isReadOnly()) {
187             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
188             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
189         }
190         if (data == null) {
191             return;
192         }
193         if (needsSyncData()) {
194             synchronizeData();
195         }
196         
197         setNodeValue(this.data + data);
198
199     } // appendData(String)
200

201     /**
202      * Remove a range of characters from the node's value. Throws a
203      * DOMException if the offset is beyond the end of the
204      * string. However, a deletion _count_ that exceeds the available
205      * data is accepted as a delete-to-end request.
206      *
207      * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
208      * greater than length, or if count is negative.
209      *
210      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is
211      * readonly.
212      */

213     public void deleteData(int offset, int count)
214         throws DOMException JavaDoc {
215         
216         internalDeleteData(offset, count, false);
217     } // deleteData(int,int)
218

219     
220     /** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
221      * to control which mutation events are spawned. This version of the
222      * deleteData operation allows us to do so. It is not intended
223      * for use by application programs.
224      */

225     void internalDeleteData (int offset, int count, boolean replace)
226     throws DOMException JavaDoc {
227         
228         CoreDocumentImpl ownerDocument = ownerDocument();
229         if (ownerDocument.errorChecking) {
230             if (isReadOnly()) {
231                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
232                 throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
233             }
234             
235             if (count < 0) {
236                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
237                 throw new DOMException JavaDoc(DOMException.INDEX_SIZE_ERR, msg);
238             }
239         }
240         
241         if (needsSyncData()) {
242             synchronizeData();
243         }
244         int tailLength = Math.max(data.length() - count - offset, 0);
245         try {
246             String JavaDoc value = data.substring(0, offset) +
247             (tailLength > 0 ? data.substring(offset + count, offset + count + tailLength) : "");
248             
249             setNodeValueInternal(value, replace);
250             
251             // notify document
252
ownerDocument.deletedText(this, offset, count);
253         }
254         catch (StringIndexOutOfBoundsException JavaDoc e) {
255             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
256             throw new DOMException JavaDoc(DOMException.INDEX_SIZE_ERR, msg);
257         }
258         
259     } // internalDeleteData(int,int,boolean)
260

261     /**
262      * Insert additional characters into the data stored in this node,
263      * at the offset specified.
264      *
265      * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
266      * greater than length.
267      *
268      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
269      */

270     public void insertData(int offset, String JavaDoc data)
271         throws DOMException JavaDoc {
272
273         internalInsertData(offset, data, false);
274         
275     } // insertData(int,int)
276

277     
278     
279     /** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
280      * to control which mutation events are spawned. This version of the
281      * insertData operation allows us to do so. It is not intended
282      * for use by application programs.
283      */

284     void internalInsertData (int offset, String JavaDoc data, boolean replace)
285     throws DOMException JavaDoc {
286         
287         CoreDocumentImpl ownerDocument = ownerDocument();
288         
289         if (ownerDocument.errorChecking && isReadOnly()) {
290             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
291             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
292         }
293         
294         if (needsSyncData()) {
295             synchronizeData();
296         }
297         try {
298             String JavaDoc value =
299                 new StringBuffer JavaDoc(this.data).insert(offset, data).toString();
300             
301             
302             setNodeValueInternal(value, replace);
303             
304             // notify document
305
ownerDocument.insertedText(this, offset, data.length());
306         }
307         catch (StringIndexOutOfBoundsException JavaDoc e) {
308             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
309             throw new DOMException JavaDoc(DOMException.INDEX_SIZE_ERR, msg);
310         }
311         
312     } // internalInsertData(int,String,boolean)
313

314     
315     
316     /**
317      * Replace a series of characters at the specified (zero-based)
318      * offset with a new string, NOT necessarily of the same
319      * length. Convenience method, equivalent to a delete followed by an
320      * insert. Throws a DOMException if the specified offset is beyond
321      * the end of the existing data.
322      *
323      * @param offset The offset at which to begin replacing.
324      *
325      * @param count The number of characters to remove,
326      * interpreted as in the delete() method.
327      *
328      * @param data The new string to be inserted at offset in place of
329      * the removed data. Note that the entire string will
330      * be inserted -- the count parameter does not affect
331      * insertion, and the new data may be longer or shorter
332      * than the substring it replaces.
333      *
334      * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
335      * greater than length, or if count is negative.
336      *
337      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is
338      * readonly.
339      */

340     public void replaceData(int offset, int count, String JavaDoc data)
341     throws DOMException JavaDoc {
342         
343         CoreDocumentImpl ownerDocument = ownerDocument();
344         
345         // The read-only check is done by deleteData()
346
// ***** This could be more efficient w/r/t Mutation Events,
347
// specifically by aggregating DOMAttrModified and
348
// DOMSubtreeModified. But mutation events are
349
// underspecified; I don't feel compelled
350
// to deal with it right now.
351
if (ownerDocument.errorChecking && isReadOnly()) {
352             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
353             throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
354         }
355         
356         if (needsSyncData()) {
357             synchronizeData();
358         }
359         
360         //notify document
361
ownerDocument.replacingData(this);
362         
363         // keep old value for document notification
364
String JavaDoc oldvalue = this.data;
365         
366         internalDeleteData(offset, count, true);
367         internalInsertData(offset, data, true);
368         
369         ownerDocument.replacedCharacterData(this, oldvalue, this.data);
370         
371     } // replaceData(int,int,String)
372

373     /**
374      * Store character data into this node.
375      *
376      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
377      */

378     public void setData(String JavaDoc value)
379         throws DOMException JavaDoc {
380         setNodeValue(value);
381     }
382
383     /**
384      * Substring is more than a convenience function. In some
385      * implementations of the DOM, where the stored data may exceed the
386      * length that can be returned in a single string, the only way to
387      * read it all is to extract it in chunks via this method.
388      *
389      * @param offset Zero-based offset of first character to retrieve.
390      * @param count Number of characters to retrieve.
391      *
392      * If the sum of offset and count exceeds the length, all characters
393      * to end of data are returned.
394      *
395      * @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
396      * greater than length, or if count is negative.
397      *
398      * @throws DOMException(WSTRING_SIZE_ERR) In some implementations,
399      * count may exceed the permitted length of strings. If so,
400      * substring() will throw this DOMException advising the user to
401      * instead retrieve the data in smaller chunks.
402      */

403     public String JavaDoc substringData(int offset, int count)
404         throws DOMException JavaDoc {
405
406         if (needsSyncData()) {
407             synchronizeData();
408         }
409         
410         int length = data.length();
411         if (count < 0 || offset < 0 || offset > length - 1) {
412             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
413             throw new DOMException JavaDoc(DOMException.INDEX_SIZE_ERR, msg);
414         }
415
416         int tailIndex = Math.min(offset + count, length);
417
418         return data.substring(offset, tailIndex);
419
420     } // substringData(int,int):String
421

422 } // class CharacterDataImpl
423
Popular Tags