OSDN Git Service

Initial revision
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / xml / libxmlj / dom / GnomeNode.java
1 /* GnomeNode.java - 
2    Copyright (C) 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package gnu.xml.libxmlj.dom;
39
40 import java.util.HashMap;
41 import java.util.Iterator;
42 import java.util.Map;
43
44 import org.w3c.dom.Document;
45 import org.w3c.dom.DocumentType;
46 import org.w3c.dom.DOMException;
47 import org.w3c.dom.NamedNodeMap;
48 import org.w3c.dom.Node;
49 import org.w3c.dom.NodeList;
50 import org.w3c.dom.Text;
51 import org.w3c.dom.UserDataHandler;
52
53 import gnu.xml.libxmlj.util.StandaloneDocumentType;
54
55 /**
56  * A DOM node implemented in libxml2.
57  *
58  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
59  */
60 class GnomeNode
61   implements Node, Comparable
62 {
63
64   /**
65    * Maps document pointers to a map of node pointers to node instances.
66    */
67   static Map instances;
68
69   /**
70    * Retrieves the node instance for the specified node pointer.
71    * This creates a new instance and adds it to the cache if required.
72    * @param doc the document pointer
73    * @param node the node pointer
74    * @param type the node type
75    */
76   static GnomeNode newInstance(final Object doc, final Object node,
77                                final int type)
78   {
79     if (doc == null)
80       {
81         throw new NullPointerException("doc");
82       }
83     if (node == null)
84       {
85         throw new NullPointerException("node");
86       }
87     if (instances == null)
88       {
89         instances = new HashMap();
90       }
91     Map docNodes = (Map) instances.get(doc);
92     if (docNodes == null)
93       {
94         docNodes = new HashMap(1024); // TODO review optimal initial capacity
95         instances.put(doc, docNodes);
96       }
97     GnomeNode nodeInstance = (GnomeNode) docNodes.get(node);
98     if (nodeInstance != null)
99       {
100         return nodeInstance; // Return cached version
101       }
102     switch (type)
103       {
104       case ELEMENT_NODE:
105         nodeInstance = new GnomeElement(node);
106         break;
107       case ATTRIBUTE_NODE:
108         nodeInstance = new GnomeAttr(node);
109         break;
110       case TEXT_NODE:
111         nodeInstance = new GnomeText(node);
112         break;
113       case CDATA_SECTION_NODE:
114         nodeInstance = new GnomeCDATASection(node);
115         break;
116       case ENTITY_REFERENCE_NODE:
117         nodeInstance = new GnomeEntityReference(node);
118         break;
119       case ENTITY_NODE:
120         nodeInstance = new GnomeEntity(node);
121         break;
122       case PROCESSING_INSTRUCTION_NODE:
123         nodeInstance = new GnomeProcessingInstruction(node);
124         break;
125       case COMMENT_NODE:
126         nodeInstance = new GnomeComment(node);
127         break;
128       case DOCUMENT_NODE:
129         nodeInstance = new GnomeDocument(node);
130         break;
131       case DOCUMENT_TYPE_NODE:
132         nodeInstance = new GnomeDocumentType(node);
133         break;
134       case DOCUMENT_FRAGMENT_NODE:
135         nodeInstance = new GnomeDocumentFragment(node);
136         break;
137       case NOTATION_NODE:
138         nodeInstance = new GnomeNotation(node);
139         break;
140       default:
141         throw new IllegalArgumentException("Unknown node type: " + type);
142       }
143     docNodes.put(node, nodeInstance);
144     return nodeInstance;
145   }
146   
147   /**
148    * Frees the specified document.
149    * This removes all its nodes from the cache.
150    */
151   static void freeDocument(final Object doc)
152   {
153     if (instances == null || doc == null)
154       {
155         return;
156       }
157     instances.remove(doc);
158     //System.out.println("Freed "+instances.remove(doc));
159   }
160   
161   /**
162    * xmlNodePtr
163    */
164   final Object id;
165
166   Map userData;
167   Map userDataHandlers;
168
169   GnomeNode(final Object id)
170   {
171     this.id = id;
172   }
173
174   public native String getNodeName();
175
176   public native String getNodeValue()
177     throws DOMException;
178
179   public native void setNodeValue(String nodeValue)
180     throws DOMException;
181
182   public native short getNodeType();
183
184   public native Node getParentNode();
185
186   public NodeList getChildNodes()
187   {
188     return new GnomeNodeList(id);
189   }
190
191   public native Node getFirstChild();
192
193   public native Node getLastChild();
194
195   public native Node getPreviousSibling();
196
197   public native Node getNextSibling();
198
199   public NamedNodeMap getAttributes()
200   {
201     return new GnomeNamedNodeMap(id, 0);
202   }
203
204   public native Document getOwnerDocument();
205
206   public Node insertBefore(Node newChild, Node refChild)
207     throws DOMException
208   {
209     if (newChild instanceof StandaloneDocumentType)
210       {
211         DocumentType dt = (DocumentType) newChild;
212         newChild = ((GnomeDocument) getOwnerDocument())
213           .createDocumentType(dt.getName(), dt.getPublicId(),
214                               dt.getSystemId());
215       }
216     if (newChild == null)
217       {
218         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
219       }
220     if (!(newChild instanceof GnomeNode))
221       {
222         throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
223       }
224     if (refChild == null || !(refChild instanceof GnomeNode))
225       {
226         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
227       }
228     return xmljInsertBefore(newChild, refChild);
229   }
230
231   private native Node xmljInsertBefore(Node newChild, Node refChild)
232     throws DOMException;
233
234   public Node replaceChild(Node newChild, Node oldChild)
235     throws DOMException
236   {
237     if (newChild instanceof StandaloneDocumentType)
238       {
239         DocumentType dt = (DocumentType) newChild;
240         newChild = ((GnomeDocument) getOwnerDocument())
241           .createDocumentType(dt.getName(), dt.getPublicId(),
242                               dt.getSystemId());
243       }
244     if (newChild == null)
245       {
246         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
247       }
248     if (!(newChild instanceof GnomeNode))
249       {
250         throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, newChild.toString());
251       }
252     if (oldChild == null || !(oldChild instanceof GnomeNode))
253       {
254         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null);
255       }
256     return xmljReplaceChild(newChild, oldChild);
257   }
258
259   private native Node xmljReplaceChild(Node newChild, Node oldChild)
260     throws DOMException;
261
262   public Node removeChild(Node oldChild)
263     throws DOMException
264   {
265     if (!(oldChild instanceof GnomeNode))
266       {
267         throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
268       }
269     return xmljRemoveChild(oldChild);
270   }
271
272   private native Node xmljRemoveChild(Node oldChild)
273     throws DOMException;
274
275   public Node appendChild(Node newChild)
276     throws DOMException
277   {
278     if (newChild instanceof StandaloneDocumentType)
279       {
280         DocumentType dt = (DocumentType) newChild;
281         newChild = ((GnomeDocument) getOwnerDocument())
282           .createDocumentType(dt.getName(), dt.getPublicId(),
283                               dt.getSystemId());
284       }
285     if (!(newChild instanceof GnomeNode))
286       {
287         throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null);
288       }
289     return xmljAppendChild(newChild);
290   }
291
292   private native Node xmljAppendChild(Node newChild)
293     throws DOMException;
294
295   public native boolean hasChildNodes();
296
297   public Node cloneNode(boolean deep)
298   {
299     Node ret = xmljCloneNode(deep);
300     notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, ret);
301     return ret;
302   }
303   
304   private native Node xmljCloneNode(boolean deep);
305
306   public native void normalize();
307
308   public boolean isSupported(String feature, String version)
309   {
310     return getOwnerDocument().getImplementation()
311       .hasFeature(feature, version);
312   }
313
314   public native String getNamespaceURI();
315
316   public native String getPrefix();
317
318   public native void setPrefix(String prefix)
319     throws DOMException;
320
321   public native String getLocalName();
322
323   public native boolean hasAttributes();
324
325   public int hashCode()
326   {
327     return id.hashCode();
328   }
329
330   public boolean equals(Object other)
331   {
332     if (other == this)
333       {
334         return true;
335       }
336     return (other instanceof GnomeNode &&
337             ((GnomeNode) other).id == id);
338   }
339
340   // DOM Level 3 methods
341
342   public native String getBaseURI();
343
344   public short compareDocumentPosition(Node other)
345     throws DOMException
346   {
347     return (short) compareTo(other);
348   }
349
350   public final int compareTo(Object other)
351   {
352     if (other instanceof GnomeNode)
353       {
354         return xmljCompareTo(other);
355       }
356     return 0;
357   }
358
359   private native int xmljCompareTo(Object other);
360   
361   public String getTextContent()
362     throws DOMException
363   {
364     switch (getNodeType())
365       {
366       case ELEMENT_NODE:
367       case ATTRIBUTE_NODE:
368       case ENTITY_NODE:
369       case ENTITY_REFERENCE_NODE:
370       case DOCUMENT_FRAGMENT_NODE:
371         StringBuffer buffer = new StringBuffer();
372         NodeList children = getChildNodes();
373         int len = children.getLength();
374         for (int i = 0; i < len; i++)
375           {
376             Node child = children.item(i);
377             String textContent = child.getTextContent();
378             if (textContent != null)
379               {
380                 buffer.append(textContent);
381               }
382           }
383         return buffer.toString();
384       case TEXT_NODE:
385       case CDATA_SECTION_NODE:
386       case COMMENT_NODE:
387       case PROCESSING_INSTRUCTION_NODE:
388         return getNodeValue();
389       default:
390         return null;
391       }
392   }
393   
394   public void setTextContent(String textContent)
395     throws DOMException
396   {
397     switch (getNodeType())
398       {
399       case ENTITY_REFERENCE_NODE:
400         // entity references are read only
401         throw new GnomeDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
402                                     null);
403       case ELEMENT_NODE:
404       case ATTRIBUTE_NODE:
405       case ENTITY_NODE:
406       case DOCUMENT_FRAGMENT_NODE:
407         NodeList children = getChildNodes();
408         int len = children.getLength();
409         for (int i = 0; i < len; i++)
410           {
411             Node child = children.item(i);
412             removeChild(child);
413           }
414         if (textContent != null)
415           {
416             Text text = getOwnerDocument().createTextNode(textContent);
417             appendChild(text);
418           }
419         break;
420       case TEXT_NODE:
421       case CDATA_SECTION_NODE:
422       case COMMENT_NODE:
423       case PROCESSING_INSTRUCTION_NODE:
424         setNodeValue(textContent);
425         break;
426       }
427   }
428   
429   public boolean isSameNode(Node other)
430   {
431     return equals(other);
432   }
433   
434   public native String lookupPrefix(String namespaceURI);
435   
436   public native boolean isDefaultNamespace(String namespaceURI);
437   
438   public native String lookupNamespaceURI(String prefix);
439   
440   public native boolean isEqualNode(Node arg);
441   
442   public Object getFeature(String feature, String version)
443   {
444     return getOwnerDocument().getImplementation()
445       .getFeature(feature, version);
446   }
447
448   public Object setUserData(String key, Object data, UserDataHandler handler)
449   {
450     // TODO handler
451     if (userData == null)
452       {
453         userData = new HashMap();
454       }
455     if (handler != null)
456       {
457         if (userDataHandlers == null)
458           {
459             userDataHandlers = new HashMap();
460           }
461         userDataHandlers.put(key, handler);
462       }
463     return userData.put(key, data);
464   }
465
466   public Object getUserData(String key)
467   {
468     if (userData == null)
469       {
470         return null;
471       }
472     return userData.get(key);
473   }
474
475   void notifyUserDataHandlers(short op, Node src, Node dst)
476   {
477     if (userDataHandlers != null)
478       {
479         for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); )
480           {
481             Map.Entry entry = (Map.Entry) i.next();
482             String key = (String) entry.getKey();
483             UserDataHandler handler = (UserDataHandler) entry.getValue();
484             Object data = userData.get(key);
485             handler.handle(op, key, data, src, dst);
486           }
487       }
488   }
489
490   public String toString()
491   {
492     StringBuffer buffer = new StringBuffer(getClass().getName());
493     buffer.append("[nodeName=");
494     buffer.append(getNodeName());
495     buffer.append("]");
496     return buffer.toString();
497   }
498
499 }