Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 716   Methods: 51
NCLOC: 386   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DocumentImpl.java 40.5% 45.8% 47.1% 44.8%
coverage coverage
 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    * $Id: DocumentImpl.java 571948 2007-09-02 10:51:37Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.xml.dom;
 21   
 22    import org.apache.commons.logging.Log;
 23    import org.apache.commons.logging.LogFactory;
 24    import org.apache.xindice.xml.NodeSource;
 25    import org.apache.xindice.xml.SymbolTable;
 26    import org.apache.xindice.xml.dom.traversal.TreeWalkerImpl;
 27   
 28    import org.w3c.dom.Attr;
 29    import org.w3c.dom.CDATASection;
 30    import org.w3c.dom.Comment;
 31    import org.w3c.dom.DOMConfiguration;
 32    import org.w3c.dom.DOMException;
 33    import org.w3c.dom.DOMImplementation;
 34    import org.w3c.dom.Document;
 35    import org.w3c.dom.DocumentFragment;
 36    import org.w3c.dom.DocumentType;
 37    import org.w3c.dom.Element;
 38    import org.w3c.dom.EntityReference;
 39    import org.w3c.dom.NamedNodeMap;
 40    import org.w3c.dom.Node;
 41    import org.w3c.dom.NodeList;
 42    import org.w3c.dom.ProcessingInstruction;
 43    import org.w3c.dom.Text;
 44    import org.w3c.dom.UserDataHandler;
 45    import org.w3c.dom.traversal.DocumentTraversal;
 46    import org.w3c.dom.traversal.NodeFilter;
 47    import org.w3c.dom.traversal.NodeIterator;
 48    import org.w3c.dom.traversal.TreeWalker;
 49   
 50    import java.io.IOException;
 51    import java.util.HashSet;
 52    import java.util.Iterator;
 53    import java.util.Set;
 54   
 55    /**
 56    * DocumentImpl
 57    *
 58    * @version $Revision: 571948 $, $Date: 2007-09-02 03:51:37 -0700 (Sun, 02 Sep 2007) $
 59    */
 60    public final class DocumentImpl extends ContainerNodeImpl
 61    implements CompressedDocument, DBDocument, DocumentTraversal {
 62   
 63    private static final Log log = LogFactory.getLog(DocumentImpl.class);
 64   
 65    private DocumentType docType;
 66    private String version;
 67    private String xmlEncoding;
 68    private String inputEncoding;
 69    private boolean standalone;
 70    private boolean strictErrorChecking;
 71    private SymbolTable symbols;
 72    private boolean readOnly;
 73    private DOMConfiguration domConfig = new DOMConfigurationImpl();
 74   
 75    /**
 76    * Create empty dirty document.
 77    */
 78  30213 public DocumentImpl() {
 79  30213 super(null, true);
 80    }
 81   
 82    /**
 83    * Create document from the compressed data.
 84    *
 85    * @param data compressed document data
 86    * @param symbols symbol table used to compress a document
 87    */
 88  43811 public DocumentImpl(byte[] data, SymbolTable symbols) {
 89  43811 super(null, data, 0, data.length);
 90  43811 this.symbols = symbols;
 91    }
 92   
 93    /**
 94    * Create document from the compressed data.
 95    *
 96    * @param data compressed document data
 97    * @param symbols symbol table used to compress a document
 98    * @param source identifies document origin
 99    */
 100  43811 public DocumentImpl(byte[] data, SymbolTable symbols, NodeSource source) {
 101  43811 this(data, symbols);
 102  43811 this.source = source;
 103    }
 104   
 105    /**
 106    * Create document from the compressed data with specified read only state.
 107    *
 108    * @param data compressed document data
 109    * @param symbols symbol table used to compress a document
 110    * @param source identifies document origin
 111    * @param readOnly if true, document will be marked read only.
 112    */
 113  0 public DocumentImpl(byte[] data, SymbolTable symbols, NodeSource source, boolean readOnly) {
 114  0 this(data, symbols, source);
 115  0 this.readOnly = readOnly;
 116    }
 117   
 118    /**
 119    * Create a compressed document out of another document.
 120    *
 121    * @param doc document to copy
 122    */
 123  0 public DocumentImpl(Document doc) {
 124  0 super(null, true);
 125   
 126  0 boolean compress = true;
 127  0 if (doc instanceof CompressedDocument) {
 128  0 CompressedDocument c = (CompressedDocument) doc;
 129  0 symbols = c.getSymbols();
 130  0 if (!c.isDirty()) {
 131  0 data = c.getDataBytes();
 132  0 pos = c.getDataPos();
 133  0 len = c.getDataLen();
 134  0 compress = false;
 135    }
 136    }
 137   
 138  0 if (compress) {
 139  0 if (symbols == null) {
 140  0 symbols = new SymbolTable();
 141    }
 142  0 data = DOMCompressor.compress(doc, symbols);
 143  0 pos = 0;
 144  0 len = data.length;
 145    }
 146   
 147  0 if (doc instanceof DBDocument) {
 148  0 source = ((DBDocument) doc).getSource();
 149    }
 150    }
 151   
 152  902132 public boolean isReadOnly() {
 153  902132 return readOnly;
 154    }
 155   
 156  278842 protected void checkLoaded() {
 157  278842 if (loaded) {
 158  216391 return;
 159    }
 160   
 161  62451 loaded = true;
 162  62451 try {
 163  62451 if (data != null) {
 164  32266 loadChildren(symbols);
 165    }
 166    } catch (IOException e) {
 167  0 if (log.isWarnEnabled()) {
 168  0 log.warn("ignored exception", e);
 169    }
 170    }
 171    }
 172   
 173  0 public boolean isCaching() {
 174  0 String cache = DBDocument.CACHE;
 175   
 176  0 int size = childNodes.getLength();
 177  0 for (int i = 0; i < size; i++) {
 178  0 Node n = childNodes.item(i);
 179  0 if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CACHE_CONTROL)) {
 180  0 cache = n.getNodeValue().trim();
 181  0 break;
 182    }
 183    }
 184   
 185  0 return (cache != null && cache.equals(CACHE));
 186    }
 187   
 188  0 public void setCaching(boolean caching) {
 189  0 int size = childNodes.getLength();
 190  0 for (int i = 0; i < size; i++) {
 191  0 Node n = childNodes.item(i);
 192  0 if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CACHE_CONTROL)) {
 193  0 n.setNodeValue(caching ? CACHE : NOCACHE);
 194  0 return;
 195    }
 196    }
 197   
 198  0 ProcessingInstruction pi = createProcessingInstruction(CACHE_CONTROL, caching ? CACHE : NOCACHE);
 199  0 insertBefore(pi, getDocumentElement());
 200    }
 201   
 202  924061 public SymbolTable getSymbols() {
 203  924061 return symbols;
 204    }
 205   
 206  169 public void setSymbols(SymbolTable symbols) {
 207  169 this.symbols = symbols;
 208    }
 209   
 210  0 public void expandSource() {
 211  0 ElementImpl e = (ElementImpl) getDocumentElement();
 212  0 if (e != null) {
 213  0 e.expandSource();
 214    }
 215    }
 216   
 217  0 public Node getNodeAtPos(int pos) {
 218  0 return null; // TODO: This
 219    }
 220   
 221  1850816 public short getNodeType() {
 222  1850815 return Node.DOCUMENT_NODE;
 223    }
 224   
 225  0 public String getNodeName() {
 226  0 return "#document";
 227    }
 228   
 229    /**
 230    * The Document Type Declaration (see <code>DocumentType</code>) associated
 231    * with this document. For HTML documents as well as XML documents without
 232    * a document type declaration this returns <code>null</code>. The DOM Level
 233    * 1 does not support editing the Document Type Declaration, therefore
 234    * <code>docType</code> cannot be altered in any way.
 235    */
 236  0 public DocumentType getDoctype() {
 237  0 return docType;
 238    }
 239   
 240  0 public void setDoctype(DocumentType docType) {
 241  0 this.docType = docType;
 242    }
 243   
 244    /**
 245    * The <code>DOMImplementation</code> object that handles this document. A
 246    * DOM application may use objects from multiple implementations.
 247    */
 248  2697 public DOMImplementation getImplementation() {
 249  2697 return DOMImplementationImpl.getInstance();
 250    }
 251   
 252    /**
 253    * Creates a <code>Text</code> node given the specified string.
 254    * @param data The data for the node.
 255    * @return The new <code>Text</code> object.
 256    */
 257  120657 public Text createTextNode(String data) {
 258  120657 return new TextImpl(this, data);
 259    }
 260   
 261    /**
 262    * This is a convenience method that allows direct access to the child
 263    * node that is the root element of the document. For HTML documents, this
 264    * is the element with the tagName "HTML".
 265    */
 266  69724 public Element getDocumentElement() {
 267  69724 checkLoaded();
 268   
 269  69724 Iterator i = childNodes.iterator();
 270  72393 while (i.hasNext()) {
 271  72393 Node node = (Node) i.next();
 272  72393 if (node.getNodeType() == Node.ELEMENT_NODE) {
 273  69724 return (Element) node;
 274    }
 275    }
 276   
 277  0 return null;
 278    }
 279   
 280    /**
 281    * Creates a <code>CDATASection</code> node whose value is the specified
 282    * string.
 283    * @param data The data for the <code>CDATASection</code> contents.
 284    * @return The new <code>CDATASection</code> object.
 285    * @exception DOMException
 286    * NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
 287    */
 288  28 public CDATASection createCDATASection(String data) throws DOMException {
 289  28 return new CDATASectionImpl(this, data);
 290    }
 291   
 292    /**
 293    * Creates an element of the type specified. Note that the instance returned
 294    * implements the Element interface, so attributes can be specified
 295    * directly on the returned object.
 296    * @param tagName The name of the element type to instantiate. For XML, this
 297    * is case-sensitive. For HTML, the <code>tagName</code> parameter may
 298    * be provided in any case, but it must be mapped to the canonical
 299    * uppercase form by the DOM implementation.
 300    * @return A new <code>Element</code> object.
 301    * @exception DOMException
 302    * INVALID_CHARACTER_ERR: Raised if the specified name contains an
 303    * invalid character.
 304    */
 305  125084 public Element createElement(String tagName) throws DOMException {
 306  125084 return new ElementImpl(this, tagName);
 307    }
 308   
 309    /**
 310    * Creates an empty <code>DocumentFragment</code> object.
 311    * @return A new <code>DocumentFragment</code>.
 312    */
 313  1 public DocumentFragment createDocumentFragment() {
 314  1 return new DocumentFragmentImpl(this);
 315    }
 316   
 317    /**
 318    * Creates an <code>Attr</code> of the given name. Note that the
 319    * <code>Attr</code> instance can then be set on an <code>Element</code>
 320    * using the <code>setAttribute</code> method.
 321    * @param name The name of the attribute.
 322    * @return A new <code>Attr</code> object.
 323    * @exception DOMException
 324    * INVALID_CHARACTER_ERR: Raised if the specified name contains an
 325    * invalid character.
 326    */
 327  136296 public Attr createAttribute(String name) throws DOMException {
 328  136296 return new AttrImpl(this, name);
 329    }
 330   
 331    /**
 332    * Creates a <code>Comment</code> node given the specified string.
 333    * @param data The data for the node.
 334    * @return The new <code>Comment</code> object.
 335    */
 336  532 public Comment createComment(String data) {
 337  532 return new CommentImpl(this, data);
 338    }
 339   
 340    /**
 341    * Creates a <code>ProcessingInstruction</code> node given the specified
 342    * name and data strings.
 343    * @param target The target part of the processing instruction.
 344    * @param data The data for the node.
 345    * @return The new <code>ProcessingInstruction</code> object.
 346    * @exception DOMException
 347    * INVALID_CHARACTER_ERR: Raised if an invalid character is specified.
 348    * <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
 349    */
 350  5869 public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException {
 351  5869 return new ProcessingInstructionImpl(this, target, data);
 352    }
 353   
 354    /**
 355    * Creates an EntityReference object.
 356    * @param name The name of the entity to reference.
 357    * @return The new <code>EntityReference</code> object.
 358    * @exception DOMException
 359    * INVALID_CHARACTER_ERR: Raised if the specified name contains an
 360    * invalid character.
 361    * <br>NOT_SUPPORTED_ERR: Raised if this document is an HTML document.
 362    */
 363  0 public EntityReference createEntityReference(String name) throws DOMException {
 364  0 return new EntityReferenceImpl(this, name);
 365    }
 366   
 367  1203 private void importNamespaces(Node source, Node target) {
 368  1203 if (target.getNodeType() == Node.ELEMENT_NODE) {
 369    // Retrieve Namespace definitions in scope
 370  1203 Set set = new HashSet();
 371  1203 Node n = source;
 372  1203 Element elem = (Element) target;
 373  1203 while (n != null) {
 374  1635 NamedNodeMap nm = n.getAttributes();
 375  1635 for (int i = 0; i < nm.getLength(); i++) {
 376  3870 Attr a = (Attr) nm.item(i);
 377  3870 String name = a.getNodeName();
 378  3870 if ((name.startsWith("xmlns:") || name.equals("xmlns")) && !set.contains(name)) {
 379  492 set.add(name);
 380  492 elem.setAttribute(name, a.getValue());
 381    }
 382    }
 383  1635 n = n.getParentNode();
 384  1635 if (n == null || n.getNodeType() == DOCUMENT_NODE || n.getNodeType() == DOCUMENT_FRAGMENT_NODE) {
 385  1203 n = null;
 386    }
 387    }
 388    }
 389    }
 390   
 391  1266 public Node importNode(Node importedNode, boolean deep) {
 392  1266 return importNode(importedNode, deep, true, true);
 393    }
 394   
 395  4433 private Node importNode(Node importedNode, boolean deep, boolean importNamespaces, boolean invokeHandler) {
 396  4433 try {
 397    // If we're a Xindice Compressed DOM Node, and share the same symbol table,
 398    // then we're golden
 399  4433 if (importedNode instanceof NodeImpl) {
 400  4433 NodeImpl impl = (NodeImpl) importedNode;
 401  4433 DocumentImpl docImpl = (DocumentImpl) impl.getOwnerDocument();
 402  4433 if (docImpl.getSymbols() != null && (docImpl.getSymbols() == symbols)) {
 403  0 NodeImpl clone = (NodeImpl) impl.cloneNode(deep, false);
 404  0 clone.setParentNode(this);
 405   
 406  0 if (importNamespaces) {
 407  0 importNamespaces(importedNode, clone);
 408    }
 409  0 if (invokeHandler) {
 410  0 invokeHandlers(UserDataHandler.NODE_IMPORTED, importedNode, clone);
 411    }
 412   
 413  0 return clone;
 414    }
 415    }
 416   
 417    // Crap, we have to do a full graph copy
 418  4433 Node result = null;
 419  4433 switch (importedNode.getNodeType()) {
 420  27 case Node.ATTRIBUTE_NODE:
 421  27 result = createAttribute(importedNode.getNodeName());
 422  27 break;
 423   
 424  0 case Node.CDATA_SECTION_NODE:
 425  0 result = createCDATASection(importedNode.getNodeValue());
 426  0 break;
 427   
 428  63 case Node.COMMENT_NODE:
 429  63 result = createComment(importedNode.getNodeValue());
 430  63 break;
 431   
 432  2619 case Node.ELEMENT_NODE:
 433  2619 Element selem = (Element) importedNode;
 434  2619 Element elem = createElement(selem.getTagName());
 435  2619 NamedNodeMap attrs = selem.getAttributes();
 436  2619 int size = attrs.getLength();
 437  2619 for (int i = 0; i < size; i++) {
 438  5115 Attr a = (Attr) attrs.item(i);
 439  5115 Attr ai = createAttribute(a.getName());
 440  5115 ai.setValue(a.getValue());
 441  5115 elem.setAttributeNode(ai);
 442    }
 443  2619 result = elem;
 444  2619 if (importNamespaces) {
 445  1203 importNamespaces(importedNode, result);
 446    }
 447  2619 break;
 448   
 449  0 case Node.ENTITY_REFERENCE_NODE:
 450  0 result = createEntityReference(importedNode.getNodeValue());
 451  0 break;
 452   
 453  0 case Node.PROCESSING_INSTRUCTION_NODE:
 454  0 result = createProcessingInstruction(importedNode.getNodeName(), importedNode.getNodeValue());
 455  0 break;
 456   
 457  1724 case Node.TEXT_NODE:
 458  1724 result = createTextNode(importedNode.getNodeValue());
 459  1724 break;
 460   
 461  0 default:
 462    // FIXME Huh?
 463    }
 464   
 465  4433 if (deep && result != null) {
 466  4433 NodeList list = importedNode.getChildNodes();
 467  4433 int size = list.getLength();
 468  4433 for (int i = 0; i < size; i++) {
 469  3167 Node n = list.item(i);
 470  3167 result.appendChild(importNode(n, deep, false, invokeHandler));
 471    }
 472   
 473  4433 if (invokeHandler) {
 474  4433 invokeHandlers(UserDataHandler.NODE_IMPORTED, importedNode, result);
 475    }
 476    }
 477   
 478  4433 return result;
 479    } catch (Exception e) {
 480  0 if (log.isWarnEnabled()) {
 481  0 log.warn("ignored exception", e);
 482    }
 483  0 return null;
 484    }
 485    }
 486   
 487  20612 public Element createElementNS(String namespaceURI, String qualifiedName) {
 488  20612 return new ElementImpl(this, qualifiedName);
 489    }
 490   
 491  986 public Attr createAttributeNS(String namespaceURI, String qualifiedName) {
 492  986 return new AttrImpl(this, qualifiedName);
 493    }
 494   
 495  471 public NodeIterator createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException {
 496  471 return new TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
 497    }
 498   
 499  0 public TreeWalker createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException {
 500  0 return new TreeWalkerImpl(root, whatToShow, filter, entityReferenceExpansion);
 501    }
 502   
 503    //
 504    // DOM Level 3 Implementation
 505    //
 506   
 507    /**
 508    * @since DOM Level 3
 509    */
 510  0 public Node adoptNode(Node src) {
 511    // If we're a Xindice DOM Node and share the same symbol table
 512    // or the adopted node has no symbol table, then we're golden
 513  0 if (src instanceof NodeImpl) {
 514  0 NodeImpl impl = (NodeImpl) src;
 515  0 DocumentImpl docImpl = (DocumentImpl) impl.getOwnerDocument();
 516  0 if (docImpl.getSymbols() == null || docImpl.getSymbols() == symbols) {
 517  0 impl.getParentNode().removeChild(impl);
 518  0 impl.setParentNode(this);
 519  0 invokeHandlers(UserDataHandler.NODE_ADOPTED, src, null);
 520  0 return impl;
 521    }
 522    }
 523   
 524  0 Node node = importNode(src, true, true, false);
 525  0 invokeHandlers(UserDataHandler.NODE_ADOPTED, src, node);
 526   
 527  0 return node;
 528    }
 529   
 530    /**
 531    * @since DOM Level 3
 532    */
 533  0 public boolean getStrictErrorChecking() {
 534  0 checkLoaded();
 535  0 return strictErrorChecking;
 536    }
 537   
 538    /**
 539    * @since DOM Level 3
 540    */
 541  0 public void setStrictErrorChecking(boolean strictErrorChecking) {
 542  0 checkReadOnly();
 543  0 checkLoaded();
 544  0 this.strictErrorChecking = strictErrorChecking;
 545    }
 546   
 547    /**
 548    * @since DOM Level 3
 549    */
 550  0 public String getDocumentURI() {
 551  0 return null;
 552    }
 553   
 554    /**
 555    * @since DOM Level 3
 556    */
 557  0 public void setDocumentURI(String documentURI) {
 558    }
 559   
 560    /**
 561    * @since DOM Level 3
 562    */
 563  0 public String getInputEncoding() {
 564  0 checkLoaded();
 565  0 return inputEncoding;
 566    }
 567   
 568  0 public void setInputEncoding(String inputEncoding) {
 569  0 checkReadOnly();
 570  0 checkLoaded();
 571  0 this.inputEncoding = inputEncoding;
 572    }
 573   
 574    /**
 575    * @since DOM Level 3
 576    */
 577  0 public String getXmlEncoding() {
 578  0 checkLoaded();
 579  0 return xmlEncoding;
 580    }
 581   
 582  0 public void setXmlEncoding(String xmlEncoding) {
 583  0 checkReadOnly();
 584  0 checkLoaded();
 585  0 this.xmlEncoding = xmlEncoding;
 586    }
 587   
 588    /**
 589    * @since DOM Level 3
 590    */
 591  0 public boolean getXmlStandalone() {
 592  0 checkLoaded();
 593  0 return standalone;
 594    }
 595   
 596    /**
 597    * @since DOM Level 3
 598    */
 599  0 public void setXmlStandalone(boolean standalone) throws DOMException {
 600  0 checkReadOnly();
 601  0 checkLoaded();
 602  0 this.standalone = standalone;
 603    }
 604   
 605    /**
 606    * @since DOM Level 3
 607    */
 608  0 public String getXmlVersion() {
 609  0 checkLoaded();
 610  0 return version;
 611    }
 612   
 613    /**
 614    * @since DOM Level 3
 615    */
 616  0 public void setXmlVersion(String version) throws DOMException {
 617  0 checkReadOnly();
 618  0 checkLoaded();
 619  0 this.version = version;
 620    }
 621   
 622    /**
 623    * @since DOM Level 3
 624    */
 625  0 public DOMConfiguration getDomConfig() {
 626  0 return domConfig;
 627    }
 628   
 629    /**
 630    * @since DOM Level 3
 631    */
 632  0 public void normalizeDocument() {
 633    }
 634   
 635    /**
 636    * Rename an existing node of type ELEMENT_NODE or ATTRIBUTE_NODE.
 637    * <p/>
 638    * When possible this simply changes the name of the given node, otherwise
 639    * this creates a new node with the specified name and replaces the
 640    * existing node with the new node as described below.
 641    * <p/>
 642    * If simply changing the name of the given node is not possible, the
 643    * following operations are performed: a new node is created, any
 644    * registered event listener is registered on the new node, any user data
 645    * attached to the old node is removed from that node, the old node is
 646    * removed from its parent if it has one, the children are moved to the
 647    * new node, if the renamed node is an Element its attributes are moved to
 648    * the new node, the new node is inserted at the position the old node used
 649    * to have in its parent's child nodes list if it has one, the user data
 650    * that was attached to the old node is attached to the new node.
 651    * <p/>
 652    * When the node being renamed is an Element only the specified attributes
 653    * are moved, default attributes originated from the DTD are updated
 654    * according to the new element name. In addition, the implementation may
 655    * update default attributes from other schemas. Applications should use
 656    * Document.normalizeDocument() to guarantee these attributes are
 657    * up-to-date.
 658    * <p/>
 659    * When the node being renamed is an Attr that is attached to an Element,
 660    * the node is first removed from the Element attributes map. Then, once
 661    * renamed, either by modifying the existing node or creating a new one as
 662    * described above, it is put back.
 663    * <p/>
 664    * In addition, <ul>
 665    * <li>a user data event NODE_RENAMED is fired,
 666    * <li>when the implementation supports the feature "MutationNameEvents",
 667    * each mutation operation involved in this method fires the appropriate
 668    * event, and in the end the event {http://www.w3.org/2001/xml-events,
 669    * DOMElementNameChanged} or {http://www.w3.org/2001/xml-events,
 670    * DOMAttributeNameChanged} is fired.
 671    * </ul>
 672    * @param n The node to rename.
 673    * @param namespaceURI The new namespace URI.
 674    * @param qualifiedName The new qualified name.
 675    * @return The renamed node. This is either the specified node or the new
 676    * node that was created to replace the specified node.
 677    * @throws DOMException NOT_SUPPORTED_ERR: Raised when the type of the
 678    * specified node is neither ELEMENT_NODE nor ATTRIBUTE_NODE, or if the
 679    * implementation does not support the renaming of the document element.
 680    * @throws DOMException INVALID_CHARACTER_ERR: Raised if the new qualified
 681    * name is not an XML name according to the XML version in use specified
 682    * in the Document.xmlVersion attribute.
 683    * @throws DOMException WRONG_DOCUMENT_ERR: Raised when the specified node
 684    * was created from a different document than this document.
 685    * @throws DOMException NAMESPACE_ERR: Raised if the qualifiedName is a
 686    * malformed qualified name, if the qualifiedName has a prefix and the
 687    * namespaceURI is null, or if the qualifiedName has a prefix that is
 688    * "xml" and the namespaceURI is different from
 689    * "http://www.w3.org/XML/1998/namespace" [XML Namespaces]. Also raised,
 690    * when the node being renamed is an attribute, if the qualifiedName, or
 691    * its prefix, is "xmlns" and the namespaceURI is different from
 692    * "http://www.w3.org/2000/xmlns/".
 693    * @since DOM Level 3
 694    */
 695  8 public Node renameNode(Node n, String namespaceURI, String qualifiedName) throws DOMException {
 696  8 if (!(n instanceof NodeImpl) || n.getOwnerDocument() != this) {
 697  0 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, "Node was created from a different document");
 698    }
 699   
 700  8 int idx = qualifiedName.indexOf(':');
 701  8 String prefix = idx >= 0 ? qualifiedName.substring(0, idx) : null;
 702   
 703  8 if (prefix != null && ("".equals(prefix) || namespaceURI == null || "".equals(namespaceURI))) {
 704  0 throw new DOMException(DOMException.NAMESPACE_ERR, "Malformed qualified name '" + qualifiedName + "'.");
 705    }
 706   
 707  8 return ((NodeImpl) n).renameNode(namespaceURI, qualifiedName, prefix);
 708    }
 709   
 710    /**
 711    * @since DOM Level 3
 712    */
 713  0 public String getTextContent() {
 714  0 return null;
 715    }
 716    }