Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 741   Methods: 35
NCLOC: 458   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
MetaData.java 46.4% 65.1% 71.4% 59.5%
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: MetaData.java 713233 2008-11-12 01:01:36Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.core.meta;
 21   
 22    import org.apache.commons.logging.Log;
 23    import org.apache.commons.logging.LogFactory;
 24    import org.apache.xindice.xml.TextWriter;
 25    import org.apache.xindice.xml.XMLSerializable;
 26    import org.apache.xindice.xml.dom.DocumentImpl;
 27   
 28    import org.w3c.dom.DOMException;
 29    import org.w3c.dom.Document;
 30    import org.w3c.dom.Element;
 31    import org.w3c.dom.Node;
 32    import org.w3c.dom.NodeList;
 33   
 34    import java.util.Date;
 35    import java.util.Enumeration;
 36    import java.util.Hashtable;
 37    import java.util.Vector;
 38   
 39    /**
 40    * Implements the MetaData interface.
 41    *
 42    * <pre>
 43    * &lt;meta&gt;
 44    * &lt;system [type="doc|col"] [href="uri"]/&gt;
 45    * &lt;attrs&gt;
 46    * &lt;attr name="name" value="value"/&gt;
 47    * &lt;attr name="name" value="value"/&gt;
 48    * &lt;/attrs&gt;
 49    * &lt;custom&gt;
 50    * ...
 51    * &lt;/custom&gt;
 52    * &lt;/meta&gt;
 53    * </pre>
 54    *
 55    * @author ku
 56    * @author Dave Viner &lt;dviner@apache.org&gt;
 57    * @version $Revision: 713233 $, $Date: 2008-11-12 01:01:36 +0000 (Wed, 12 Nov 2008) $
 58    */
 59    public class MetaData implements XMLSerializable {
 60   
 61    private static final Log log = LogFactory.getLog(MetaData.class);
 62   
 63    public static final short UNKNOWN = 0;
 64    public static final short COLLECTION = 1;
 65    public static final short DOCUMENT = 2;
 66    public static final short LINK = 3;
 67   
 68    public static final String NS_URI = "http://apache.org/xindice/metadata";
 69    public static final boolean USE_NS = true;
 70   
 71    private static final String E_META = "meta";
 72    private static final String E_SYSTEM = "system";
 73    private static final String E_ATTRS = "attrs";
 74    private static final String E_ATTR = "attr";
 75    private static final String E_CUSTOM = "custom";
 76    private static final String E_CREATED = "created";
 77    private static final String E_MODIFIED = "modified";
 78   
 79    private static final String A_NAME = "name";
 80    private static final String A_VALUE = "value";
 81    private static final String A_TYPE = "type";
 82    private static final String A_HREF = "href";
 83   
 84    private static final Enumeration EMPTY = new Vector().elements();
 85   
 86    private transient boolean dirty;
 87    private transient long created;
 88    private transient long modified;
 89    private transient String owner;
 90   
 91    private short type = UNKNOWN;
 92    private String link;
 93    private Hashtable attrs;
 94    private Document custom;
 95   
 96   
 97  5011 public MetaData() {
 98    }
 99   
 100    /**
 101    * @param owner the owner of this metadata.
 102    */
 103  18 public MetaData(String owner) {
 104  18 this.owner = owner;
 105    }
 106   
 107   
 108    /**
 109    * @param type the type of object for this metadata
 110    * @param owner the owner of this metadata
 111    * @param created the time when this was created
 112    * @param modified the time when this was modified.
 113    */
 114  10011 public MetaData(short type, String owner, long created, long modified) {
 115  10011 this.type = type;
 116  10011 this.owner = owner;
 117  10011 this.created = created;
 118  10011 this.modified = modified;
 119    }
 120   
 121    /**
 122    * @param elem an XML representation of the desired metadata.
 123    */
 124  0 public MetaData(Element elem) {
 125  0 streamFromXML(elem);
 126    }
 127   
 128    /**
 129    * Returns whether this MetaData is dirty
 130    *
 131    * @return boolean
 132    */
 133  0 public final boolean isDirty() {
 134  0 return dirty;
 135    }
 136   
 137    /**
 138    * Reset the dirtiness of this object
 139    *
 140    * @param dirty
 141    */
 142  9932 public final void setDirty(boolean dirty) {
 143  9932 this.dirty = dirty;
 144    }
 145   
 146    /**
 147    * Returns the time of creation
 148    * @return long creation time
 149    */
 150  44 public long getCreatedTime() {
 151  44 return created;
 152    }
 153   
 154    /**
 155    * Returns the time of last modification
 156    * @return long last modified time
 157    */
 158  44 public long getLastModifiedTime() {
 159  44 return modified;
 160    }
 161   
 162    /**
 163    * Returns the type of the owner object, e.g., COLLECTION,
 164    * DOCUMENT, or LINK
 165    * @return short the object type
 166    */
 167  5034 public short getType() {
 168  5034 return type;
 169    }
 170   
 171    /**
 172    * Returns the canonical name of the owner object.
 173    * @return String the canonical name of the owner object
 174    */
 175  0 public String getOwner() {
 176  0 return owner;
 177    }
 178   
 179    /**
 180    * Returns enumeration of all attributes
 181    * @return Enumeration of attributes
 182    */
 183  18 public Enumeration getAttributeKeys() {
 184  18 if (attrs == null) {
 185  9 return EMPTY;
 186    }
 187   
 188  9 return attrs.keys();
 189    }
 190   
 191    /**
 192    * Retrieves the attribute by name
 193    * @param name the attribute name
 194    * @return String the value of attribute, or null if not found
 195    */
 196  20 public Object getAttribute(final Object name) {
 197  20 if (attrs == null) {
 198  0 return null;
 199    }
 200   
 201  20 return attrs.get(name);
 202    }
 203   
 204  0 public Boolean getAttributeAsBoolean(final Object name) {
 205  0 Object o = getAttribute(name);
 206  0 if (o == null) {
 207  0 return null;
 208    }
 209   
 210  0 if (o instanceof Boolean) {
 211  0 return (Boolean) o;
 212    }
 213   
 214  0 if (o instanceof Number) {
 215  0 Number n = (Number) o;
 216  0 return n.intValue() != 0 ? Boolean.TRUE : Boolean.FALSE;
 217    }
 218   
 219  0 return Boolean.valueOf(o.toString());
 220    }
 221   
 222  0 public Integer getAttributeAsInteger(final Object name) {
 223  0 Object o = getAttribute(name);
 224  0 if (o == null) {
 225  0 return null;
 226    }
 227   
 228  0 if (o instanceof Integer) {
 229  0 return (Integer) o;
 230    }
 231   
 232  0 if (o instanceof Number) {
 233  0 Number n = (Number) o;
 234  0 return new Integer(n.intValue());
 235    }
 236   
 237  0 try {
 238  0 return new Integer(o.toString());
 239    } catch (Exception e) {
 240  0 return null;
 241    }
 242    }
 243   
 244  0 public Long getAttributeAsLong(final Object name) {
 245  0 Object o = getAttribute(name);
 246  0 if (o == null) {
 247  0 return null;
 248    }
 249   
 250  0 if (o instanceof Long) {
 251  0 return (Long) o;
 252    }
 253   
 254  0 if (o instanceof Number) {
 255  0 Number n = (Number) o;
 256  0 return new Long(n.longValue());
 257    }
 258   
 259  0 try {
 260  0 return new Long(o.toString());
 261    } catch (Exception e) {
 262  0 return null;
 263    }
 264    }
 265   
 266  0 public Short getAttributeAsShort(final Object name) {
 267  0 Object o = getAttribute(name);
 268  0 if (o == null) {
 269  0 return null;
 270    }
 271   
 272  0 if (o instanceof Short) {
 273  0 return (Short) o;
 274    }
 275   
 276  0 if (o instanceof Number) {
 277  0 Number n = (Number) o;
 278  0 return new Short(n.shortValue());
 279    }
 280   
 281  0 try {
 282  0 return new Short(o.toString());
 283    } catch (Exception e) {
 284  0 return null;
 285    }
 286    }
 287   
 288    /**
 289    * Sets the attribute by name
 290    * @param name the attribute name
 291    * @param value the attribute value
 292    * @return Object the old value, if any
 293    */
 294  10 public Object setAttribute(final Object name, final Object value) {
 295  10 if (attrs == null) {
 296  10 attrs = new Hashtable();
 297  10 dirty = true;
 298    }
 299   
 300  10 Object prev = attrs.put(name, value);
 301  10 if (prev == null || !prev.equals(value)) {
 302  10 dirty = true;
 303    }
 304   
 305  10 return prev;
 306    }
 307   
 308    /**
 309    * Remove an attribute by name
 310    * @param name the attribute to remove
 311    * @return Object the removed value
 312    */
 313  0 public Object removeAttribute(final Object name) {
 314  0 if (attrs == null) {
 315  0 return null;
 316    }
 317   
 318  0 Object prev = attrs.remove(name);
 319  0 if (prev != null) {
 320  0 dirty = true;
 321    }
 322   
 323  0 return prev;
 324    }
 325   
 326    /**
 327    * Returns the (optional) custom meta document
 328    * @return Document the custom meta document
 329    */
 330  23 public Document getCustomDocument() {
 331  23 return custom;
 332    }
 333   
 334    /**
 335    * Sets the (optional) custom meta document
 336    * @param doc the Document
 337    */
 338  4 public void setCustomDocument(Document doc) {
 339  4 this.custom = doc;
 340  4 this.dirty = true;
 341    }
 342   
 343    /**
 344    * Copies from another meta data
 345    * @param meta the meta to copy from
 346    */
 347  0 public void copyFrom(final MetaData meta) {
 348  0 this.created = meta.getCreatedTime();
 349  0 this.modified = meta.getLastModifiedTime();
 350  0 this.owner = meta.getOwner();
 351  0 this.type = meta.getType();
 352  0 copyDataFrom(meta);
 353    }
 354   
 355    /**
 356    * Copies only user data (link, attributes, custom document) from another meta data
 357    * @param meta the meta to copy from
 358    */
 359  18 public void copyDataFrom(final MetaData meta) {
 360  18 this.link = meta.getLinkTargetURI();
 361  18 this.attrs = null;
 362  18 for (Enumeration e = meta.getAttributeKeys(); e.hasMoreElements();) {
 363  9 Object key = e.nextElement();
 364  9 Object value = meta.getAttribute(key);
 365  9 if (this.attrs == null) {
 366  9 this.attrs = new Hashtable();
 367    }
 368  9 this.attrs.put(key, value);
 369    }
 370   
 371  18 this.custom = null;
 372  18 Document doc = meta.getCustomDocument();
 373  18 if (doc != null) {
 374  3 this.custom = new DocumentImpl();
 375  3 this.custom.appendChild(
 376    this.custom.importNode(doc.getDocumentElement(), true));
 377    }
 378   
 379  18 this.dirty = false;
 380    }
 381   
 382    /**
 383    * Returns the linked target URI, if this is a link
 384    * @return String the URI of the linked target
 385    */
 386  18 public String getLinkTargetURI() {
 387  18 return link;
 388    }
 389   
 390    //
 391    // Serialization to/from XML
 392    //
 393   
 394    /**
 395    * Stream this MetaData into an xml document
 396    * @param doc the xml document to be populated.
 397    */
 398  4928 public final Element streamToXML(Document doc) throws DOMException {
 399  4928 return streamToXML(doc, true);
 400    }
 401   
 402    /**
 403    * Stream this MetaData into an xml document
 404    * @param doc the xml document to populate
 405    * @param includeTime whether or not to include the create/modified times
 406    * @return Element the root element
 407    */
 408  4959 public final Element streamToXML(Document doc, boolean includeTime)
 409    throws DOMException {
 410   
 411  4959 Element root;
 412  4959 if (!USE_NS) {
 413  0 root = doc.createElement(E_META);
 414    } else {
 415  4959 root = doc.createElementNS(NS_URI, E_META);
 416  4959 root.setAttribute("xmlns", NS_URI);
 417    }
 418   
 419  4959 Element systemElement;
 420  4959 if (!USE_NS) {
 421  0 systemElement = doc.createElement(E_SYSTEM);
 422    } else {
 423  4959 systemElement = doc.createElementNS(NS_URI, E_SYSTEM);
 424    }
 425  4959 systemElement.setAttribute(A_TYPE, getTypeString(type));
 426  4959 root.appendChild(systemElement);
 427  4959 if (includeTime) {
 428  4959 Element timeElement;
 429  4959 if (!USE_NS) {
 430  0 timeElement = doc.createElement(E_ATTR);
 431    } else {
 432  4959 timeElement = doc.createElementNS(NS_URI, E_ATTR);
 433    }
 434  4959 timeElement.setAttribute(A_NAME, E_CREATED);
 435  4959 timeElement.setAttribute(A_VALUE, Long.toString(created));
 436  4959 systemElement.appendChild(timeElement);
 437   
 438  4959 if (!USE_NS) {
 439  0 timeElement = doc.createElement(E_ATTR);
 440    } else {
 441  4959 timeElement = doc.createElementNS(NS_URI, E_ATTR);
 442    }
 443  4959 timeElement.setAttribute(A_NAME, E_MODIFIED);
 444  4959 timeElement.setAttribute(A_VALUE, Long.toString(modified));
 445  4959 systemElement.appendChild(timeElement);
 446    }
 447  4959 if (link != null) {
 448  0 systemElement.setAttribute(A_HREF, link);
 449    }
 450   
 451  4959 if (attrs != null && attrs.size() > 0) {
 452  21 Element attrsElement;
 453  21 if (!USE_NS) {
 454  0 attrsElement = doc.createElement(E_ATTRS);
 455    } else {
 456  21 attrsElement = doc.createElementNS(NS_URI, E_ATTRS);
 457    }
 458  21 root.appendChild(attrsElement);
 459   
 460  21 for (Enumeration e = attrs.keys(); e.hasMoreElements();) {
 461  21 Object key = e.nextElement();
 462  21 Object value = attrs.get(key);
 463  21 if (key == null) {
 464  0 continue;
 465    }
 466   
 467  21 Element attrElement;
 468  21 if (!USE_NS) {
 469  0 attrElement = doc.createElement(E_ATTR);
 470    } else {
 471  21 attrElement = doc.createElementNS(NS_URI, E_ATTR);
 472    }
 473  21 attrsElement.appendChild(attrElement);
 474   
 475  21 attrElement.setAttribute(A_NAME, key.toString());
 476  21 if (value != null) {
 477  21 attrElement.setAttribute(A_VALUE, value.toString());
 478    }
 479    }
 480    }
 481   
 482  4959 if (custom != null) {
 483  6 Element customElement;
 484  6 if (!USE_NS) {
 485  0 customElement = doc.createElement(E_CUSTOM);
 486    } else {
 487  6 customElement = doc.createElementNS(NS_URI, E_CUSTOM);
 488    }
 489   
 490  6 customElement.appendChild(
 491    doc.importNode(custom.getDocumentElement(), true));
 492  6 root.appendChild(customElement);
 493    }
 494   
 495  4959 return root;
 496    }
 497   
 498    /**
 499    * Given some xml, populate the metadata.
 500    * @param source The xml to populate metadata with
 501    */
 502  2545 public final void streamFromXML(Element source)
 503    throws DOMException {
 504  2545 streamFromXML(source, true);
 505    }
 506   
 507    /**
 508    * Given some xml, populate the metadata.
 509    * @param source The xml to populate the metadata with
 510    * @param includeTime Whether or not to reset the create/modified times
 511    */
 512  2564 public final void streamFromXML(Element source, boolean includeTime)
 513    throws DOMException {
 514  2564 this.link = null;
 515  2564 this.attrs = null;
 516  2564 this.custom = null;
 517   
 518  2564 NodeList list = source.getChildNodes();
 519  2564 for (int i = 0; i < list.getLength(); i++) {
 520  2591 Node node = list.item(i);
 521  2591 if (node.getNodeType() != Node.ELEMENT_NODE) {
 522  0 continue;
 523    }
 524   
 525  2591 Element element = (Element) node;
 526  2591 String elementName = element.getNodeName();
 527    // String prefix = element.getPrefix();
 528   
 529  2591 if (E_SYSTEM.equals(elementName)) {
 530  2564 String attrStr = element.getAttribute(A_TYPE);
 531  2564 if (attrStr != null) {
 532  2564 this.type = parseTypeString(attrStr);
 533    }
 534   
 535  2564 if (this.type == LINK) {
 536  0 this.link = element.getAttribute(A_HREF);
 537    }
 538   
 539  2564 if (includeTime) {
 540  2564 NodeList children = element.getChildNodes();
 541  2564 for (int j = 0; j < children.getLength(); j++) {
 542  5128 Node childNode = children.item(j);
 543  5128 if (!(childNode instanceof Element)) {
 544  0 continue;
 545    }
 546   
 547  5128 Element child = (Element) childNode;
 548  5128 String childName = child.getNodeName();
 549   
 550   
 551  5128 if (E_ATTR.equals(childName)) {
 552  5128 String nameStr = child.getAttribute(A_NAME);
 553  5128 String valueStr = child.getAttribute(A_VALUE);
 554  5128 if (nameStr != null && valueStr != null) {
 555  5128 if (E_CREATED.equals(nameStr)) {
 556  2564 this.created = Long.parseLong(valueStr);
 557  2564 } else if (E_MODIFIED.equals(nameStr)) {
 558  2564 this.modified = Long.parseLong(valueStr);
 559    }
 560    }
 561    } else {
 562  0 if (log.isDebugEnabled()) {
 563  0 log.debug("Ignorning unknown child elem " + childName);
 564    }
 565    }
 566    }
 567    }
 568  27 } else if (E_ATTRS.equals(elementName)) {
 569  21 NodeList attrList = element.getElementsByTagName(E_ATTR);
 570  21 for (int j = 0; j < attrList.getLength(); j++) {
 571  21 Element e = (Element) attrList.item(j);
 572   
 573  21 String attrName = e.getAttribute(A_NAME);
 574  21 if (attrName == null) {
 575  0 continue;
 576    }
 577   
 578  21 if (this.attrs == null) {
 579  21 this.attrs = new Hashtable();
 580    }
 581  21 this.attrs.put(attrName, e.getAttribute(A_VALUE));
 582    }
 583  6 } else if (E_CUSTOM.equals(elementName)) {
 584  6 this.custom = new DocumentImpl();
 585  6 Node custdoc = this.custom.importNode(element.getFirstChild(), true);
 586   
 587    /* if you want really verbose debugging try this */
 588  6 if (log.isTraceEnabled()) {
 589  0 log.trace("Appending custom element " + elementName
 590    + "\nwhose complete original content is: \n" + TextWriter.toString(source)
 591    + "\nwhose original content is: \n" + TextWriter.toString(element)
 592    + "\nwhose imported content is: \n" + TextWriter.toString(custdoc));
 593    }
 594  6 this.custom.appendChild(custdoc);
 595    } else {
 596    // ignore
 597  0 if (log.isDebugEnabled()) {
 598  0 log.debug("ignoring unknown xml element " + elementName);
 599    }
 600    }
 601    }
 602    }
 603   
 604    //
 605    // Support methods
 606    //
 607   
 608    /**
 609    * Return a string representing which type passed in.
 610    * It will be either doc, col, link, none.
 611    * @param type The type you want translated.
 612    * @return String representing this type
 613    */
 614  4963 public static String getTypeString(short type) {
 615  4963 switch (type) {
 616  2015 case DOCUMENT:
 617  2015 return "doc";
 618  2945 case COLLECTION:
 619  2945 return "col";
 620  0 case LINK:
 621  0 return "link";
 622  3 default:
 623  3 return "none";
 624    }
 625    }
 626   
 627    /**
 628    * Return a short representing the string given.
 629    * The string should be doc, col, or link.
 630    * @param str The string to parse
 631    * @return short The short for this string.
 632    */
 633  2564 public static short parseTypeString(final String str) {
 634  2564 if (str.equalsIgnoreCase("doc")) {
 635  100 return DOCUMENT;
 636    }
 637  2464 if (str.equalsIgnoreCase("col")) {
 638  2464 return COLLECTION;
 639    }
 640  0 if (str.equalsIgnoreCase("link")) {
 641  0 return LINK;
 642    }
 643   
 644  0 return UNKNOWN;
 645    }
 646   
 647    //
 648    // Modifiers
 649    //
 650   
 651    /**
 652    * Determine whether this obect has created or modified times set
 653    * @return boolean
 654    */
 655  4947 public boolean hasContext() {
 656  4947 return (created > 0 || modified > 0);
 657    }
 658   
 659    /**
 660    * Set the created and modified times. If 0 value is passed,
 661    * time is not changed.
 662    *
 663    * @param created the new creation time
 664    * @param modified the new modified time
 665    */
 666  4916 public void setContext(long created, long modified) {
 667  4916 if (created > 0) {
 668  2471 this.created = created;
 669    }
 670  4916 if (modified > 0) {
 671  4916 this.modified = modified;
 672    }
 673    }
 674   
 675    /**
 676    * Set the type for this object.
 677    * If the type is already set to the value passed in, nothing is changed.
 678    * @param type the type for this object.
 679    */
 680  2465 public void setType(short type) {
 681  2465 if (this.type != type) {
 682  2465 this.type = type;
 683  2465 this.dirty = true;
 684    }
 685    }
 686   
 687    /**
 688    * Set the owner of this object
 689    * @param owner the owner to be ass
 690    */
 691  5004 public void setOwner(String owner) {
 692  5004 if (owner != this.owner ||
 693    null == owner ||
 694    null == this.owner ||
 695    !owner.equals(this.owner)) {
 696  5004 this.owner = owner;
 697  5004 this.dirty = true;
 698    }
 699    }
 700   
 701  0 public void setLinkTargetURI(String link) {
 702  0 if (link != this.link ||
 703    null == link ||
 704    null == this.link ||
 705    !link.equals(this.link)) {
 706  0 this.link = link;
 707  0 this.dirty = true;
 708    }
 709    }
 710   
 711    /**
 712    * Return a string representing this MetaData
 713    * It will look like:
 714    * META[doc owner=OWNER created=CREATED modified=MODIFIED link=LINK
 715    * attrs=ATTRS]
 716    *
 717    * @return String
 718    */
 719  4 public String toString() {
 720  4 StringBuffer buffer = new StringBuffer();
 721  4 buffer.append("META[");
 722  4 buffer.append(getTypeString(type));
 723  4 if (owner != null) {
 724  4 buffer.append(" owner=").append(owner);
 725    }
 726  4 if (created > 0) {
 727  0 buffer.append(" created=").append(new Date(created));
 728    }
 729  4 if (modified > 0) {
 730  0 buffer.append(" modified=").append(new Date(modified));
 731    }
 732  4 if (link != null) {
 733  0 buffer.append(" link=").append(link);
 734    }
 735  4 if (attrs != null) {
 736  0 buffer.append(" attrs=").append(attrs);
 737    }
 738  4 buffer.append("]");
 739  4 return buffer.toString();
 740    }
 741    }