1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package javax.imageio.metadata;
19
20import java.util.ArrayList;
21import java.util.List;
22
23import org.w3c.dom.Attr;
24import org.w3c.dom.DOMException;
25import org.w3c.dom.Document;
26import org.w3c.dom.Element;
27import org.w3c.dom.NamedNodeMap;
28import org.w3c.dom.Node;
29import org.w3c.dom.NodeList;
30import org.w3c.dom.TypeInfo;
31import org.w3c.dom.UserDataHandler;
32
33//???AWT
34//import org.w3c.dom.TypeInfo;
35//import org.w3c.dom.UserDataHandler;
36
37/**
38 * The Class IIOMetadataNode represents a node of the (DOM-style) metadata tree.
39 *
40 * @since Android 1.0
41 */
42public class IIOMetadataNode implements Element, NodeList {
43
44    /**
45     * The node name.
46     */
47    private String nodeName;
48
49    /**
50     * The node value.
51     */
52    private String nodeValue;
53
54    /**
55     * The attributes.
56     */
57    private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList<IIOMetadataNode>());
58
59    /**
60     * The parent node.
61     */
62    private IIOMetadataNode parent;
63
64    /**
65     * The first child node.
66     */
67    private IIOMetadataNode firstChild;
68
69    /**
70     * The last child node.
71     */
72    private IIOMetadataNode lastChild;
73
74    /**
75     * The previous sibling.
76     */
77    private IIOMetadataNode previousSibling;
78
79    /**
80     * The next sibling.
81     */
82    private IIOMetadataNode nextSibling;
83
84    /**
85     * The number of children.
86     */
87    private int nChildren;
88
89    /**
90     * The user object associated with this node.
91     */
92    private Object userObject;
93
94    /**
95     * The text content of this node.
96     */
97    private String textContent;
98
99    /**
100     * Instantiates a new empty node.
101     */
102    public IIOMetadataNode() {
103    }
104
105    /**
106     * Instantiates a new empty node with the specified name.
107     *
108     * @param nodeName
109     *            the node name.
110     */
111    public IIOMetadataNode(String nodeName) {
112        this.nodeName = nodeName;
113    }
114
115    /**
116     * Instantiates a new IIOMetadataNode with the specified name and value.
117     *
118     * @param nodeName
119     *            the node name.
120     * @param nodeValue
121     *            the node value.
122     */
123    private IIOMetadataNode(String nodeName, String nodeValue) {
124        this.nodeName = nodeName;
125        this.nodeValue = nodeValue;
126    }
127
128    public String getTagName() {
129        return nodeName;
130    }
131
132    public String getAttribute(String name) {
133        Attr attrNode = (Attr)attrs.getNamedItem(name);
134        return (attrNode == null) ? "" : attrNode.getValue();
135    }
136
137    public void setAttribute(String name, String value) throws DOMException {
138        Attr attr = (Attr)attrs.getNamedItem(name);
139        if (attr != null) {
140            attr.setValue(value);
141        } else {
142            attrs.list.add(new IIOMetadataAttr(name, value, this));
143        }
144    }
145
146    public void removeAttribute(String name) throws DOMException {
147        IIOMetadataAttr attr = (IIOMetadataAttr)attrs.getNamedItem(name);
148        if (attr != null) {
149            attr.setOwnerElement(null);
150            attrs.list.remove(attr);
151        }
152    }
153
154    public Attr getAttributeNode(String name) {
155        return (Attr)attrs.getNamedItem(name);
156    }
157
158    public Attr setAttributeNode(Attr newAttr) throws DOMException {
159        // Check if this attribute is already in use.
160        Element owner = newAttr.getOwnerElement();
161        if (owner != null) {
162            if (owner == this) { // Replacing an attribute node by itself has no
163                // effect
164                return null;
165            } else {
166                throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR,
167                        "Attribute is already in use");
168            }
169        }
170
171        String name = newAttr.getName();
172        Attr oldAttr = getAttributeNode(name);
173        if (oldAttr != null) {
174            removeAttributeNode(oldAttr);
175        }
176
177        IIOMetadataAttr iioAttr;
178        if (newAttr instanceof IIOMetadataAttr) {
179            iioAttr = (IIOMetadataAttr)newAttr;
180            iioAttr.setOwnerElement(this);
181        } else {
182            iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this);
183        }
184
185        attrs.list.add(iioAttr);
186
187        return oldAttr;
188    }
189
190    public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
191        if (!attrs.list.remove(oldAttr)) { // Not found
192            throw new DOMException(DOMException.NOT_FOUND_ERR, "No such attribute!");
193        }
194
195        ((IIOMetadataAttr)oldAttr).setOwnerElement(null);
196
197        return oldAttr;
198    }
199
200    public NodeList getElementsByTagName(String name) {
201        ArrayList<IIOMetadataNode> nodes = new ArrayList<IIOMetadataNode>();
202
203        // Non-recursive tree walk
204        Node pos = this;
205
206        while (pos != null) {
207            if (pos.getNodeName().equals(name)) {
208                nodes.add((IIOMetadataNode)pos);
209            }
210
211            Node nextNode = pos.getFirstChild();
212
213            while (nextNode == null) {
214                if (pos == this) {
215                    break;
216                }
217
218                nextNode = pos.getNextSibling();
219
220                if (nextNode == null) {
221                    pos = pos.getParentNode();
222
223                    if (pos == null || pos == this) {
224                        nextNode = null;
225                        break;
226                    }
227                }
228            }
229            pos = nextNode;
230        }
231
232        return new IIOMetadataNodeList(nodes);
233    }
234
235    public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
236        return getAttribute(localName);
237    }
238
239    public void setAttributeNS(String namespaceURI, String qualifiedName, String value)
240            throws DOMException {
241        setAttribute(qualifiedName, value);
242    }
243
244    public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
245        removeAttribute(localName);
246    }
247
248    public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
249        return getAttributeNode(localName);
250    }
251
252    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
253        return setAttributeNode(newAttr);
254    }
255
256    public NodeList getElementsByTagNameNS(String namespaceURI, String localName)
257            throws DOMException {
258        return getElementsByTagName(localName);
259    }
260
261    public boolean hasAttribute(String name) {
262        return attrs.getNamedItem(name) != null;
263    }
264
265    public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
266        return hasAttribute(localName);
267    }
268
269    // ???AWT
270    /*
271     * public TypeInfo getSchemaTypeInfo() { throw new
272     * DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); }
273     */
274
275    /**
276     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
277     * 3)</i>
278     * <p>
279     * If the parameter isId is true, this method declares the specified
280     * attribute to be a user-determined ID attribute . This affects the value
281     * of Attr.isId and the behavior of Document.getElementById, but does not
282     * change any schema that may be in use, in particular this does not affect
283     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
284     * for the parameter isId to undeclare an attribute for being a
285     * user-determined ID attribute. To specify an attribute by local name and
286     * namespace URI, use the setIdAttributeNS method.
287     * </p>
288     *
289     * @param name
290     *            the name of the attribute.
291     * @param isId
292     *            the flag which determines whether this attribute is of type
293     *            ID.
294     * @throws DOMException
295     *             if a DOM error occurred while setting the attribute type.
296     *             <p>
297     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
298     *             <br>
299     *             NOT_FOUND_ERR: Raised if the specified node is not an
300     *             attribute of this element.
301     *             </p>
302     */
303    public void setIdAttribute(String name, boolean isId) throws DOMException {
304        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
305    }
306
307    /**
308     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
309     * 3)</i>
310     * <p>
311     * If the parameter isId is true, this method declares the specified
312     * attribute to be a user-determined ID attribute . This affects the value
313     * of Attr.isId and the behavior of Document.getElementById, but does not
314     * change any schema that may be in use, in particular this does not affect
315     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
316     * for the parameter isId to undeclare an attribute for being a
317     * user-determined ID attribute.
318     * </p>
319     *
320     * @param namespaceURI
321     *            the namespace URI of the attribute.
322     * @param localName
323     *            the local name of the attribute.
324     * @param isId
325     *            the flag which determines whether this attribute is of type
326     *            ID.
327     * @throws DOMException
328     *             if a DOM error occurred while setting the attribute type.
329     *             <p>
330     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
331     *             <br>
332     *             NOT_FOUND_ERR: Raised if the specified node is not an
333     *             attribute of this element.
334     *             </p>
335     */
336    public void setIdAttributeNS(String namespaceURI, String localName, boolean isId)
337            throws DOMException {
338        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
339    }
340
341    /**
342     * <i>Description copied from interface: org.w3c.dom.Element (DOM Level
343     * 3)</i>
344     * <p>
345     * If the parameter isId is true, this method declares the specified
346     * attribute to be a user-determined ID attribute . This affects the value
347     * of Attr.isId and the behavior of Document.getElementById, but does not
348     * change any schema that may be in use, in particular this does not affect
349     * the Attr.schemaTypeInfo of the specified Attr node. Use the value false
350     * for the parameter isId to undeclare an attribute for being a
351     * user-determined ID attribute.
352     * </p>
353     *
354     * @param idAttr
355     *            the attribute node.
356     * @param isId
357     *            the flag which determines whether this attribute is of type
358     *            ID.
359     * @throws DOMException
360     *             if a DOM error occurred while setting the attribute type.
361     *             <p>
362     *             NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
363     *             <br>
364     *             NOT_FOUND_ERR: Raised if the specified node is not an
365     *             attribute of this element.
366     *             </p>
367     */
368    public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
369        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
370    }
371
372    public String getNodeName() {
373        return nodeName;
374    }
375
376    public String getNodeValue() throws DOMException {
377        return nodeValue;
378    }
379
380    public void setNodeValue(String nodeValue) throws DOMException {
381        this.nodeValue = nodeValue;
382    }
383
384    public short getNodeType() {
385        return ELEMENT_NODE;
386    }
387
388    public Node getParentNode() {
389        return parent;
390    }
391
392    public NodeList getChildNodes() {
393        return this;
394    }
395
396    public Node getFirstChild() {
397        return firstChild;
398    }
399
400    public Node getLastChild() {
401        return lastChild;
402    }
403
404    public Node getPreviousSibling() {
405        return previousSibling;
406    }
407
408    public Node getNextSibling() {
409        return nextSibling;
410    }
411
412    public NamedNodeMap getAttributes() {
413        return attrs;
414    }
415
416    public Document getOwnerDocument() {
417        return null;
418    }
419
420    public Node insertBefore(Node newChild, Node refChild) throws DOMException {
421        if (newChild == null) {
422            throw new IllegalArgumentException("newChild == null!");
423        }
424
425        IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild;
426        IIOMetadataNode refIIOChild = (IIOMetadataNode)refChild;
427
428        newIIOChild.parent = this;
429
430        if (refIIOChild == null) {
431            newIIOChild.nextSibling = null;
432            newIIOChild.previousSibling = lastChild;
433
434            // Fix this node
435            lastChild = newIIOChild;
436            if (firstChild == null) {
437                firstChild = newIIOChild;
438            }
439        } else {
440            newIIOChild.nextSibling = refIIOChild;
441            newIIOChild.previousSibling = refIIOChild.previousSibling;
442
443            // Fix this node
444            if (firstChild == refIIOChild) {
445                firstChild = newIIOChild;
446            }
447
448            // Fix next node
449            if (refIIOChild != null) {
450                refIIOChild.previousSibling = newIIOChild;
451            }
452        }
453
454        // Fix prev node
455        if (newIIOChild.previousSibling != null) {
456            newIIOChild.previousSibling.nextSibling = newIIOChild;
457        }
458
459        nChildren++;
460
461        return newIIOChild;
462    }
463
464    public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
465        if (newChild == null) {
466            throw new IllegalArgumentException("newChild == null!");
467        }
468
469        IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild;
470        IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild;
471
472        IIOMetadataNode next = oldIIOChild.nextSibling;
473        IIOMetadataNode previous = oldIIOChild.previousSibling;
474
475        // Fix new node
476        newIIOChild.parent = this;
477        newIIOChild.nextSibling = next;
478        newIIOChild.previousSibling = previous;
479
480        // Fix this node
481        if (lastChild == oldIIOChild) {
482            lastChild = newIIOChild;
483        }
484        if (firstChild == oldIIOChild) {
485            firstChild = newIIOChild;
486        }
487
488        // Fix siblings
489        if (next != null) {
490            next.previousSibling = newIIOChild;
491        }
492        if (previous != null) {
493            previous.nextSibling = newIIOChild;
494        }
495
496        // Fix old child
497        oldIIOChild.parent = null;
498        oldIIOChild.nextSibling = next;
499        oldIIOChild.previousSibling = previous;
500
501        return oldIIOChild;
502    }
503
504    public Node removeChild(Node oldChild) throws DOMException {
505        if (oldChild == null) {
506            throw new IllegalArgumentException("oldChild == null!");
507        }
508
509        IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild;
510
511        // Fix next and previous
512        IIOMetadataNode previous = oldIIOChild.previousSibling;
513        IIOMetadataNode next = oldIIOChild.nextSibling;
514
515        if (previous != null) {
516            previous.nextSibling = next;
517        }
518        if (next != null) {
519            next.previousSibling = previous;
520        }
521
522        // Fix this node
523        if (lastChild == oldIIOChild) {
524            lastChild = previous;
525        }
526        if (firstChild == oldIIOChild) {
527            firstChild = next;
528        }
529        nChildren--;
530
531        // Fix old child
532        oldIIOChild.parent = null;
533        oldIIOChild.previousSibling = null;
534        oldIIOChild.nextSibling = null;
535
536        return oldIIOChild;
537    }
538
539    public Node appendChild(Node newChild) throws DOMException {
540        return insertBefore(newChild, null);
541    }
542
543    public boolean hasChildNodes() {
544        return nChildren != 0;
545    }
546
547    public Node cloneNode(boolean deep) {
548        IIOMetadataNode cloned = new IIOMetadataNode(nodeName);
549        cloned.setUserObject(getUserObject());
550
551        if (deep) { // Clone recursively
552            IIOMetadataNode c = firstChild;
553            while (c != null) {
554                cloned.insertBefore(c.cloneNode(true), null);
555                c = c.nextSibling;
556            }
557        }
558
559        return cloned; // To change body of implemented methods use File |
560        // Settings | File Templates.
561    }
562
563    public void normalize() {
564        // Do nothing
565    }
566
567    public boolean isSupported(String feature, String version) {
568        return false;
569    }
570
571    public String getNamespaceURI() {
572        return null;
573    }
574
575    public String getPrefix() {
576        return null;
577    }
578
579    public void setPrefix(String prefix) throws DOMException {
580        // Do nothing
581    }
582
583    public String getLocalName() {
584        return nodeName;
585    }
586
587    public boolean hasAttributes() {
588        return attrs.list.size() > 0;
589    }
590
591    /**
592     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
593     * <p>
594     * The absolute base URI of this node or null if the implementation wasn't
595     * able to obtain an absolute URI. This value is computed as described in.
596     * However, when the Document supports the feature "HTML" [DOM Level 2
597     * HTML], the base URI is computed using first the value of the href
598     * attribute of the HTML BASE element if any, and the value of the
599     * documentURI attribute from the Document interface otherwise.
600     * </p>
601     *
602     * @return the string representation of the absolute base URI.
603     */
604    public String getBaseURI() {
605        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
606    }
607
608    /**
609     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
610     * <p>
611     * Compares the reference node, i.e. the node on which this method is being
612     * called, with a node, i.e. the one passed as a parameter, with regard to
613     * their position in the document and according to the document order.
614     * </p>
615     *
616     * @param other
617     *            the node to compare against the reference node.
618     * @return Returns how the node is positioned relatively to the reference
619     *         node.
620     * @throws DOMException
621     *             NOT_SUPPORTED_ERR: when the compared nodes are from different
622     *             DOM implementations that do not coordinate to return
623     *             consistent implementation-specific results.
624     */
625    public short compareDocumentPosition(Node other) throws DOMException {
626        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
627    }
628
629    /**
630     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
631     * <p>
632     * This attribute returns the text content of this node and its descendants.
633     * When it is defined to be null, setting it has no effect. On setting, any
634     * possible children this node may have are removed and, if it the new
635     * string is not empty or null, replaced by a single Text node containing
636     * the string this attribute is set to. On getting, no serialization is
637     * performed, the returned string does not contain any markup. No whitespace
638     * normalization is performed and the returned string does not contain the
639     * white spaces in element content (see the attribute
640     * Text.isElementContentWhitespace). Similarly, on setting, no parsing is
641     * performed either, the input string is taken as pure textual content. The
642     * string returned is made of the text content of this node depending on its
643     * type, as defined below:
644     * <table>
645     * <tr>
646     * <td><strong>Node type</strong></td>
647     * <td><strong>Content</strong></td>
648     * </tr>
649     * <tr>
650     * <td>ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
651     * DOCUMENT_FRAGMENT_NODE</td>
652     * <td>concatenation of the textContent attribute value of every child node,
653     * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the
654     * empty string if the node has no children.</td>
655     * </tr>
656     * <tr>
657     * <td>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE,
658     * PROCESSING_INSTRUCTION_NODE</td>
659     * <td>nodeValue</td>
660     * </tr>
661     * <tr>
662     * <td>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
663     * <td>null</td>
664     * </tr>
665     * </table>
666     * </p>
667     *
668     * @return the text content depending on the type of this node.
669     * @throws DOMException
670     *             DOMSTRING_SIZE_ERR: Raised when it would return more
671     *             characters than fit in a DOMString variable on the
672     *             implementation platform.
673     */
674    public String getTextContent() throws DOMException {
675        return textContent;
676    }
677
678    /**
679     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
680     * <p>
681     * This attribute returns the text content of this node and its descendants.
682     * When it is defined to be null, setting it has no effect. On setting, any
683     * possible children this node may have are removed and, if it the new
684     * string is not empty or null, replaced by a single Text node containing
685     * the string this attribute is set to. On getting, no serialization is
686     * performed, the returned string does not contain any markup. No whitespace
687     * normalization is performed and the returned string does not contain the
688     * white spaces in element content (see the attribute
689     * Text.isElementContentWhitespace). Similarly, on setting, no parsing is
690     * performed either, the input string is taken as pure textual content. The
691     * string returned is made of the text content of this node depending on its
692     * type, as defined below:
693     * <table>
694     * <tr>
695     * <td><strong>Node type</strong></td>
696     * <td><strong>Content</strong></td>
697     * </tr>
698     * <tr>
699     * <td>ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
700     * DOCUMENT_FRAGMENT_NODE</td>
701     * <td>concatenation of the textContent attribute value of every child node,
702     * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the
703     * empty string if the node has no children.</td>
704     * </tr>
705     * <tr>
706     * <td>TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE,
707     * PROCESSING_INSTRUCTION_NODE</td>
708     * <td>nodeValue</td>
709     * </tr>
710     * <tr>
711     * <td>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
712     * <td>null</td>
713     * </tr>
714     * </table>
715     * </p>
716     *
717     * @param textContent
718     *            the text content for this node.
719     * @throws DOMException
720     *             NO_MODIFICATION_ALLOWED_ERR: Raised when the node is
721     *             readonly.
722     */
723    public void setTextContent(String textContent) throws DOMException {
724        this.textContent = textContent;
725    }
726
727    /**
728     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
729     * <p>
730     * Returns whether this node is the same node as the given one. This method
731     * provides a way to determine whether two Node references returned by the
732     * implementation reference the same object. When two Node references are
733     * references to the same object, even if through a proxy, the references
734     * may be used completely interchangeably, such that all attributes have the
735     * same values and calling the same DOM method on either reference always
736     * has exactly the same effect.
737     * </p>
738     *
739     * @param other
740     *            the node to test against.
741     * @return true, if the nodes are the same, false otherwise.
742     */
743    public boolean isSameNode(Node other) {
744        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
745    }
746
747    /**
748     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
749     * <p>
750     * Look up the prefix associated to the given namespace URI, starting from
751     * this node. The default namespace declarations are ignored by this method.
752     * See for details on the algorithm used by this method.
753     * </p>
754     *
755     * @param namespaceURI
756     *            the namespace URI to look for.
757     * @return the associated namespace prefix if found or null if none is
758     *         found. If more than one prefix are associated to the namespace
759     *         prefix, the returned namespace prefix is implementation
760     *         dependent.
761     */
762    public String lookupPrefix(String namespaceURI) {
763        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
764    }
765
766    /**
767     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
768     * <p>
769     * This method checks if the specified namespaceURI is the default namespace
770     * or not.
771     * </p>
772     *
773     * @param namespaceURI
774     *            the namespace URI to look for.
775     * @return true, if the specified namespaceURI is the default namespace,
776     *         false otherwise.
777     */
778    public boolean isDefaultNamespace(String namespaceURI) {
779        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
780    }
781
782    /**
783     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
784     * <p>
785     * Look up the namespace URI associated to the given prefix, starting from
786     * this node. See for details on the algorithm used by this method.
787     * </p>
788     *
789     * @param prefix
790     *            the prefix to look for. If this parameter is null, the method
791     *            will return the default namespace URI if any.
792     * @return the associated namespace URI or null if none is found.
793     */
794    public String lookupNamespaceURI(String prefix) {
795        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
796    }
797
798    /**
799     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
800     * <p>
801     * Tests whether two nodes are equal. This method tests for equality of
802     * nodes, not sameness (i.e., whether the two nodes are references to the
803     * same object) which can be tested with Node.isSameNode(). All nodes that
804     * are the same will also be equal, though the reverse may not be true. Two
805     * nodes are equal if and only if the following conditions are satisfied:
806     * <p>
807     * <li>The two nodes are of the same type.</li>
808     * <li>The following string attributes are equal: nodeName, localName,
809     * namespaceURI, prefix, nodeValue . This is: they are both null, or they
810     * have the same length and are character for character identical.</li>
811     * <li>The attributes NamedNodeMaps are equal. This is: they are both null,
812     * or they have the same length and for each node that exists in one map
813     * there is a node that exists in the other map and is equal, although not
814     * necessarily at the same index.</li>
815     * <li>The childNodes NodeLists are equal. This is: they are both null, or
816     * they have the same length and contain equal nodes at the same index. Note
817     * that normalization can affect equality; to avoid this, nodes should be
818     * normalized before being compared.</li>
819     * </p>
820     * For two DocumentType nodes to be equal, the following conditions must
821     * also be satisfied:
822     * <p>
823     * <li>The following string attributes are equal: publicId, systemId,
824     * internalSubset.</li>
825     * <li>The entities NamedNodeMaps are equal.</li>
826     * <li>The notations NamedNodeMaps are equal.</li>
827     * </p>
828     * On the other hand, the following do not affect equality: the
829     * ownerDocument, baseURI, and parentNode attributes, the specified
830     * attribute for Attr nodes, the schemaTypeInfo attribute for Attr and
831     * Element nodes, the Text.isElementContentWhitespace attribute for Text
832     * nodes, as well as any user data or event listeners registered on the
833     * nodes. </p>
834     * <p>
835     * Note: As a general rule, anything not mentioned in the description above
836     * is not significant in consideration of equality checking. Note that
837     * future versions of this specification may take into account more
838     * attributes and implementations conform to this specification are expected
839     * to be updated accordingly.
840     * </p>
841     *
842     * @param arg
843     *            the node to compare equality with.
844     * @return true, if the nodes are equal, false otherwise.
845     */
846    public boolean isEqualNode(Node arg) {
847        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
848    }
849
850    /**
851     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
852     * <p>
853     * This method returns a specialized object which implements the specialized
854     * APIs of the specified feature and version, as specified in. The
855     * specialized object may also be obtained by using binding-specific casting
856     * methods but is not necessarily expected to, as discussed in. This method
857     * also allow the implementation to provide specialized objects which do not
858     * support the Node interface.
859     * </p>
860     *
861     * @param feature
862     *            the name of the feature requested. Note that any plus sign "+"
863     *            prepended to the name of the feature will be ignored since it
864     *            is not significant in the context of this method.
865     * @param version
866     *            this is the version number of the feature to test.
867     * @return the object which implements the specialized APIs of the specified
868     *         feature and version, if any, or null if there is no object which
869     *         implements interfaces associated with that feature. If the
870     *         DOMObject returned by this method implements the Node interface,
871     *         it must delegate to the primary core Node and not return results
872     *         inconsistent with the primary core Node such as attributes,
873     *         childNodes, etc.
874     */
875    public Object getFeature(String feature, String version) {
876        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
877    }
878
879    // ???AWT
880    /*
881     * public Object setUserData(String key, Object data, UserDataHandler
882     * handler) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
883     * "Method not supported"); }
884     */
885
886    /**
887     * <i>Description copied from interface: org.w3c.dom.Node (DOM Level 3)</i>
888     * <p>
889     * Retrieves the object associated to a key on a this node. The object must
890     * first have been set to this node by calling setUserData with the same
891     * key.
892     * </p>
893     *
894     * @param key
895     *            the key the object is associated to.
896     * @return the DOMUserData associated to the given key on this node, or null
897     *         if there was none.
898     */
899    public Object getUserData(String key) {
900        throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
901    }
902
903    public Node item(int index) {
904        if (index < 0 || index >= nChildren) {
905            return null;
906        }
907
908        Node n;
909        for (n = getFirstChild(); index > 0; index--) {
910            n = n.getNextSibling();
911        }
912
913        return n;
914    }
915
916    public int getLength() {
917        return nChildren;
918    }
919
920    /**
921     * Gets the user object associated with this node.
922     *
923     * @return the user object associated with this node.
924     */
925    public Object getUserObject() {
926        return userObject;
927    }
928
929    public TypeInfo getSchemaTypeInfo() {
930        throw new UnsupportedOperationException();
931    }
932
933    public Object setUserData(String key, Object data, UserDataHandler handler) {
934        throw new UnsupportedOperationException();
935    }
936
937    /**
938     * Sets the user object associated with this node.
939     *
940     * @param userObject
941     *            the new user object associated with this node.
942     */
943    public void setUserObject(Object userObject) {
944        this.userObject = userObject;
945    }
946
947    /**
948     * The Class IIOMetadataAttr.
949     */
950    private class IIOMetadataAttr extends IIOMetadataNode implements Attr {
951
952        /**
953         * The owner element.
954         */
955        private Element ownerElement;
956
957        /**
958         * Instantiates a new iIO metadata attr.
959         *
960         * @param name
961         *            the name.
962         * @param value
963         *            the value.
964         * @param owner
965         *            the owner.
966         */
967        public IIOMetadataAttr(String name, String value, Element owner) {
968            super(name, value);
969            this.ownerElement = owner;
970        }
971
972        public String getName() {
973            return getNodeName();
974        }
975
976        public boolean getSpecified() {
977            return true;
978        }
979
980        public String getValue() {
981            return nodeValue;
982        }
983
984        public void setValue(String value) throws DOMException {
985            nodeValue = value;
986        }
987
988        public Element getOwnerElement() {
989            return ownerElement;
990        }
991
992        /**
993         * Sets the owner element.
994         *
995         * @param ownerElement
996         *            the new owner element.
997         */
998        public void setOwnerElement(Element ownerElement) {
999            this.ownerElement = ownerElement;
1000        }
1001
1002        /**
1003         * @return
1004         */
1005        public boolean isId() {
1006            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported");
1007        }
1008
1009        @Override
1010        public short getNodeType() {
1011            return ATTRIBUTE_NODE;
1012        }
1013    }
1014
1015    /**
1016     * The Class IIOMetadataNodeList.
1017     */
1018    private class IIOMetadataNodeList implements NodeList, NamedNodeMap {
1019
1020        /**
1021         * The list.
1022         */
1023        private List<IIOMetadataNode> list;
1024
1025        /**
1026         * Instantiates a new iIO metadata node list.
1027         *
1028         * @param list
1029         *            the list.
1030         */
1031        IIOMetadataNodeList(List<IIOMetadataNode> list) {
1032            this.list = list;
1033        }
1034
1035        public Node item(int index) {
1036            try {
1037                return list.get(index);
1038            } catch (IndexOutOfBoundsException e) {
1039                return null;
1040            }
1041        }
1042
1043        public int getLength() {
1044            return list.size();
1045        }
1046
1047        public Node getNamedItem(String name) {
1048            for (IIOMetadataNode node : list) {
1049                if (name.equals(node.getNodeName())) {
1050                    return node;
1051                }
1052            }
1053            return null;
1054        }
1055
1056        public Node setNamedItem(Node arg) throws DOMException {
1057            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1058                    "This NamedNodeMap is read-only!");
1059        }
1060
1061        public Node removeNamedItem(String name) throws DOMException {
1062            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1063                    "This NamedNodeMap is read-only!");
1064        }
1065
1066        public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException {
1067            return getNamedItem(localName);
1068        }
1069
1070        public Node setNamedItemNS(Node arg) throws DOMException {
1071            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1072                    "This NamedNodeMap is read-only!");
1073        }
1074
1075        public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException {
1076            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1077                    "This NamedNodeMap is read-only!");
1078        }
1079    }
1080}
1081