Clover coverage report -
Coverage timestamp: Sun Sep 7 2008 23:05:09 GMT
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  22831 public DocumentImpl() {
 79  22831 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  29238 public DocumentImpl(byte[] data, SymbolTable symbols) {
 89  29238 super(null, data, 0, data.length);
 90  29238 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  29238 public DocumentImpl(byte[] data, SymbolTable symbols, NodeSource source) {
 101  29238 this(data, symbols);
 102  29238 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  688630 public boolean isReadOnly() {
 153  688630 return readOnly;
 154    }
 155   
 156  144297 protected void checkLoaded() {
 157  144297 if (loaded) {
 158  103663 return;
 159    }
 160   
 161  40634 loaded = true;
 162  40634 try {
 163  40634 if (data != null) {
 164  17831 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  600744 public SymbolTable getSymbols() {
 203  600745 return symbols;
 204    }
 205   
 206  166 public void setSymbols(SymbolTable symbols) {
 207  166 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  1216987 public short getNodeType() {
 222  1216987 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  2679 public DOMImplementation getImplementation() {
 249  2679 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  78011 public Text createTextNode(String data) {
 258  78011 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  26618 public Element getDocumentElement() {
 267  26618 checkLoaded();
 268   
 269  26618 Iterator i = childNodes.iterator();
 270  29263 while (i.hasNext()) {
 271  29263 Node node = (Node) i.next();
 272  29263 if (node.getNodeType() == Node.ELEMENT_NODE) {
 273  26618 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  95420 public Element createElement(String tagName) throws DOMException {
 306  95420 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  114415 public Attr createAttribute(String name) throws DOMException {
 328  114415 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  10412 public Comment createComment(String data) {
 337  10412 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  5806 public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException {
 351  5806 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  969 private void importNamespaces(Node source, Node target) {
 368  969 if (target.getNodeType() == Node.ELEMENT_NODE) {
 369    // Retrieve Namespace definitions in scope
 370  969 Set set = new HashSet();
 371  969 Node n = source;
 372  969 Element elem = (Element) target;
 373  969 while (n != null) {
 374  1125 NamedNodeMap nm = n.getAttributes();
 375  1125 for (int i = 0; i < nm.getLength(); i++) {
 376  2661 Attr a = (Attr) nm.item(i);
 377  2661 String name = a.getNodeName();
 378  2661 if ((name.startsWith("xmlns:") || name.equals("xmlns")) && !set.contains(name)) {
 379  261 set.add(name);
 380  261 elem.setAttribute(name, a.getValue());
 381    }
 382    }
 383  1125 n = n.getParentNode();
 384  1125 if (n == null || n.getNodeType() == DOCUMENT_NODE || n.getNodeType() == DOCUMENT_FRAGMENT_NODE) {
 385  969 n = null;
 386    }
 387    }
 388    }
 389    }
 390   
 391  1020 public Node importNode(Node importedNode, boolean deep) {
 392  1020 return importNode(importedNode, deep, true, true);
 393    }
 394   
 395  3725 private Node importNode(Node importedNode, boolean deep, boolean importNamespaces, boolean invokeHandler) {
 396  3725 try {
 397    // If we're a Xindice Compressed DOM Node, and share the same symbol table,
 398    // then we're golden
 399  3725 if (importedNode instanceof NodeImpl) {
 400  3725 NodeImpl impl = (NodeImpl) importedNode;
 401  3725 DocumentImpl docImpl = (DocumentImpl) impl.getOwnerDocument();
 402  3725 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  3725 Node result = null;
 419  3725 switch (importedNode.getNodeType()) {
 420  15 case Node.ATTRIBUTE_NODE:
 421  15 result = createAttribute(importedNode.getNodeName());
 422  15 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  2166 case Node.ELEMENT_NODE:
 433  2166 Element selem = (Element) importedNode;
 434  2166 Element elem = createElement(selem.getTagName());
 435  2166 NamedNodeMap attrs = selem.getAttributes();
 436  2166 int size = attrs.getLength();
 437  2166 for (int i = 0; i < size; i++) {
 438  3410 Attr a = (Attr) attrs.item(i);
 439  3410 Attr ai = createAttribute(a.getName());
 440  3410 ai.setValue(a.getValue());
 441  3410 elem.setAttributeNode(ai);
 442    }
 443  2166 result = elem;
 444  2166 if (importNamespaces) {
 445  969 importNamespaces(importedNode, result);
 446    }
 447  2166 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  1481 case Node.TEXT_NODE:
 458  1481 result = createTextNode(importedNode.getNodeValue());
 459  1481 break;
 460   
 461  0 default:
 462