Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 730   Methods: 67
NCLOC: 558   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
UnversionedNode.java 75.9% 83.5% 85.1% 81.7%
coverage coverage
 1    /*
 2    * JBoss, Home of Professional Open Source
 3    *
 4    * Distributable under LGPL license.
 5    * See terms of license at gnu.org.
 6    */
 7    package org.jboss.cache;
 8   
 9    import org.apache.commons.logging.Log;
 10    import org.apache.commons.logging.LogFactory;
 11    import org.jboss.cache.lock.IdentityLock;
 12    import org.jboss.cache.marshall.MethodCall;
 13    import org.jboss.cache.marshall.MethodCallFactory;
 14    import org.jboss.cache.marshall.MethodDeclarations;
 15    import org.jboss.cache.optimistic.DataVersion;
 16    import org.jboss.cache.transaction.GlobalTransaction;
 17    import org.jboss.cache.util.MapCopy;
 18   
 19    import java.util.Collections;
 20    import java.util.HashMap;
 21    import java.util.HashSet;
 22    import java.util.Map;
 23    import java.util.Set;
 24    import java.util.concurrent.ConcurrentHashMap;
 25   
 26    /**
 27    * Basic data node class. Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
 28    * {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}, defined in {@link org.jboss.cache.NodeSPI}.
 29    *
 30    * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
 31    * @since 2.0.0
 32    */
 33    public class UnversionedNode<K, V> extends AbstractNode<K, V> implements NodeSPI<K, V>
 34    {
 35   
 36    /**
 37    * Default output indent for printing.
 38    */
 39    private static final int INDENT = 4;
 40   
 41    /**
 42    * Debug log.
 43    */
 44    private static Log log = LogFactory.getLog(UnversionedNode.class);
 45   
 46    /**
 47    * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
 48    */
 49    private boolean childrenLoaded = false;
 50   
 51    /**
 52    * True if data has been loaded from the cache loader.
 53    */
 54    private boolean dataLoaded = false;
 55   
 56    /**
 57    * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
 58    * locking is not needed.
 59    */
 60    private transient IdentityLock lock_ = null;
 61   
 62    /**
 63    * A reference of the CacheImpl instance.
 64    */
 65    private transient CacheImpl<K, V> cache;
 66   
 67    /**
 68    * Map of general data keys to values.
 69    */
 70    private final Map<K, V> data = new HashMap<K, V>();
 71   
 72    /**
 73    * Constructs a new node with an FQN of Root.
 74    */
 75  0 public UnversionedNode()
 76    {
 77  0 this.fqn = Fqn.ROOT;
 78    }
 79   
 80    /**
 81    * Constructs a new node with a name, etc.
 82    *
 83    * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
 84    * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
 85    * this object's {@link #data} field.
 86    */
 87  181022 protected UnversionedNode(Object child_name, Fqn fqn, Map<K, V> data, boolean mapSafe, CacheSPI<K, V> cache)
 88    {
 89  181022 init(child_name, fqn, cache);
 90  181022 if (data != null)
 91    {
 92  10291 this.data.putAll(data);// ? is this safe
 93    }
 94    }
 95   
 96    /**
 97    * Initializes with a name and FQN and cache.
 98    */
 99  181022 private void init(Object child_name, Fqn fqn, CacheSPI<K, V> cache)
 100    {
 101  181022 if (cache == null)
 102    {
 103  0 throw new IllegalArgumentException("no cache init for " + fqn);
 104    }
 105  181022 this.cache = (CacheImpl) cache;
 106  181022 this.fqn = fqn;
 107  181022 if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
 108    {
 109  0 throw new IllegalArgumentException("Child " + child_name + " must be last part of " + fqn);
 110    }
 111    }
 112   
 113    /**
 114    * Returns a parent by checking the TreeMap by name.
 115    */
 116  115861 public NodeSPI<K, V> getParent()
 117    {
 118  115861 if (fqn.isRoot())
 119    {
 120  5 return null;
 121    }
 122  115856 return cache.peek(fqn.getParent(), true);
 123    }
 124   
 125  15670285 private synchronized void initLock()
 126    {
 127  15670265 if (lock_ == null)
 128    {
 129  180118 lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
 130    }
 131    }
 132   
 133  344346 private synchronized Map<Object, Node<K, V>> children()
 134    {
 135  344346 if (children == null)
 136    {
 137  9489 if (getFqn().isRoot())
 138    {
 139  2243 children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
 140    }
 141    else
 142    {
 143    // Less segments to save memory
 144  7246 children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
 145    }
 146    }
 147  344346 return children;
 148    }
 149   
 150  0 public CacheSPI<K, V> getCache()
 151    {
 152  0 return cache;
 153    }
 154   
 155  492 public boolean getChildrenLoaded()
 156    {
 157  492 return childrenLoaded;
 158    }
 159   
 160  88099 public void setChildrenLoaded(boolean flag)
 161    {
 162  88099 childrenLoaded = flag;
 163    }
 164   
 165  522 public V get(K key)
 166    {
 167  522 return cache.get(getFqn(), key);
 168    }
 169   
 170  463808 public V getDirect(K key)
 171    {
 172  463808 return data == null ? null : data.get(key);
 173    }
 174   
 175   
 176  58 private boolean isReadLocked()
 177    {
 178  58 return lock_ != null && lock_.isReadLocked();
 179    }
 180   
 181  58 private boolean isWriteLocked()
 182    {
 183  58 return lock_ != null && lock_.isWriteLocked();
 184    }
 185   
 186  15670285 public IdentityLock getLock()
 187    {
 188  15670229 initLock();
 189  15670285 return lock_;
 190    }
 191   
 192  427 public Map<K, V> getData()
 193    {
 194  0 if (cache == null) return Collections.emptyMap();
 195  427 Map<K, V> dMap = new HashMap<K, V>();
 196  427 for (K k : cache.getKeys(getFqn()))
 197    {
 198  30508 dMap.put(k, cache.get(fqn, k));
 199    }
 200  427 return Collections.unmodifiableMap(dMap);
 201    }
 202   
 203  1566854 public Map<K, V> getDataDirect()
 204    {
 205  1566854 return new MapCopy<K, V>(data);
 206    }
 207   
 208  131 public V put(K key, V value)
 209    {
 210  131 return cache.put(getFqn(), key, value);
 211    }
 212   
 213  406969 public V putDirect(K key, V value)
 214    {
 215  406969 return data.put(key, value);
 216    }
 217   
 218  166381 public NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx)
 219    {
 220  166381 return getOrCreateChild(child_name, gtx, true);
 221    }
 222   
 223  166381 private NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx, boolean createIfNotExists)
 224    {
 225   
 226  166381 NodeSPI child;
 227  166381 if (child_name == null)
 228    {
 229  0 throw new IllegalArgumentException("null child name");
 230    }
 231   
 232  166381 child = (NodeSPI) children().get(child_name);
 233  166381 InvocationContext ctx = cache.getInvocationContext();
 234  166381 if (createIfNotExists && child == null)
 235    {
 236    // construct the new child outside the synchronized block to avoid
 237    // spending any more time than necessary in the synchronized section
 238  166125 Fqn child_fqn = new Fqn(this.fqn, child_name);
 239  166125 NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
 240  166125 if (newChild == null)
 241    {
 242  0 throw new IllegalStateException();
 243    }
 244  166125 synchronized (this)
 245    {
 246    // check again to see if the child exists
 247    // after acquiring exclusive lock
 248  166125 child = (NodeSPI) children().get(child_name);
 249  166125 if (child == null)
 250    {
 251  166123 cache.getNotifier().notifyNodeCreated(child_fqn, true, ctx);
 252  166122 child = newChild;
 253  166122 children.put(child_name, child);
 254  166122 if (gtx != null)
 255    {
 256  17738 MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
 257    child_fqn, false);
 258  17738 cache.addUndoOperation(gtx, undo_op);
 259    // add the node name to the list maintained for the current tx
 260    // (needed for abort/rollback of transaction)
 261    // cache.addNode(gtx, child.getFqn());
 262    }
 263    }
 264    }
 265   
 266    // notify if we actually created a new child
 267  166124 if (newChild == child)
 268    {
 269  166122 if (log.isTraceEnabled())
 270    {
 271  0 log.trace("created child: fqn=" + child_fqn);
 272    }
 273  166122 cache.getNotifier().notifyNodeCreated(child_fqn, false, ctx);
 274    }
 275    }
 276  166380 return child;
 277   
 278    }
 279   
 280  0 public V remove(K key)
 281    {
 282  0 return cache.remove(getFqn(), key);
 283    }
 284   
 285  3535 public V removeDirect(K key)
 286    {
 287  0 if (data == null) return null;
 288  3535 return data.remove(key);
 289    }
 290   
 291  345 public void printDetails(StringBuffer sb, int indent)
 292    {
 293  345 printDetailsInMap(sb, indent);
 294    }
 295   
 296    /**
 297    * Returns a debug string.
 298    */
 299  72 @Override
 300    public String toString()
 301    {
 302  72 StringBuffer sb = new StringBuffer();
 303  72 sb.append(getClass().getSimpleName());
 304  72 if (deleted)
 305    {
 306  0 sb.append(" (deleted) [ ").append(fqn);
 307    }
 308    else
 309    {
 310  72 sb.append("[ ").append(fqn);
 311    }
 312  72 if (data != null)
 313    {
 314  72 synchronized (data)
 315    {
 316  72 sb.append(" data=").append(data.keySet());
 317    }
 318    }
 319  72 if (children != null && !children.isEmpty())
 320    {
 321  8 sb.append(" child=").append(getChildrenDirect(false));
 322    }
 323  72 if (lock_ != null)
 324    {
 325  58 if (isReadLocked())
 326    {
 327  8 sb.append(" RL");
 328    }
 329  58 if (isWriteLocked())
 330    {
 331  0 sb.append(" WL");
 332    }
 333    }
 334  72 sb.append("]");
 335  72 return sb.toString();
 336    }
 337   
 338  2412 public Node<K, V> addChild(Fqn f)
 339    {
 340  2412 Fqn nf = new Fqn(getFqn(), f);
 341  2412 cache.put(nf, null);
 342  2412 return getChild(f);
 343    }
 344   
 345  1018 public void addChildDirect(NodeSPI<K, V> child)
 346    {
 347  1018 if (child.getFqn().getParent().equals(getFqn()))
 348    {
 349  1018 synchronized (this)
 350    {
 351  1018 children().put(child.getFqn().getLastElement(), child);
 352    }
 353    }
 354    else
 355  0 throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "]. Can only add direct children.");
 356    }
 357   
 358  166382 public NodeSPI<K, V> addChildDirect(Fqn f)
 359    {
 360  166382 if (f.size() == 1)
 361    {
 362  166381 GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
 363  166381 return getOrCreateChild(f.getLastElement(), gtx);
 364    }
 365    else
 366    {
 367  1 throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
 368    }
 369   
 370    }
 371   
 372  1894 public void clearData()
 373    {
 374  1894 cache.removeData(getFqn());
 375    }
 376   
 377  6236 public void clearDataDirect()
 378    {
 379  6258 if (data != null) data.clear();
 380    }
 381   
 382  31874 public Node<K, V> getChild(Fqn fqn)
 383    {
 384  31874 return cache.get(new Fqn(getFqn(), fqn));
 385    }
 386   
 387  21 public NodeSPI<K, V> getChildDirect(Fqn fqn)
 388    {
 389  21 if (fqn.size() == 1)
 390    {
 391  18 return getChildDirect(fqn.getLastElement());
 392    }
 393    else
 394    {
 395  3 NodeSPI currentNode = this;
 396  3 for (int i = 0; i < fqn.size(); i++)
 397    {
 398  6 Object nextChildName = fqn.get(i);
 399  6 currentNode = currentNode.getChildDirect(nextChildName);
 400  1 if (currentNode == null) return null;
 401    }
 402  2 return currentNode;
 403    }
 404    }
 405   
 406  2042 public Set<Object> getChildrenNames()
 407    {
 408  2042 return cache.getChildrenNames(getFqn());
 409    }
 410   
 411  106061 public Set<Object> getChildrenNamesDirect()
 412    {
 413  106061 return children == null ? Collections.emptySet() : new HashSet(children.keySet());
 414    //return childrenNames();
 415    }
 416   
 417  16 public Set<K> getKeys()
 418    {
 419  16 Set<K> keys = cache.getKeys(getFqn());
 420  16 return (Set<K>) (keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys));
 421    }
 422   
 423  2670 public Set<K> getKeysDirect()
 424    {
 425  2670 if (data == null)
 426    {
 427  0 return Collections.emptySet();
 428    }
 429  2670 return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
 430    }
 431   
 432  240 public boolean hasChild(Fqn f)
 433    {
 434  240 return getChild(f) != null;
 435    }
 436   
 437  0 public V putIfAbsent(K k, V v)
 438    {
 439    // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
 440  0 synchronized (this)
 441    {
 442  0 if (!getKeys().contains(k))
 443  0 return put(k, v);
 444    else
 445  0 return get(k);
 446    }
 447    }
 448   
 449  0 public V replace(K key, V value)
 450    {
 451    // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
 452  0 synchronized (this)
 453    {
 454  0 if (getKeys().contains(key))
 455    {
 456  0 return put(key, value);
 457    }
 458    else
 459  0 return null;
 460    }
 461    }
 462   
 463  0 public boolean replace(K key, V oldValue, V newValue)
 464    {
 465    // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
 466  0 synchronized (this)
 467    {
 468  0 if (oldValue.equals(get(key)))
 469    {
 470  0 put(key, newValue);
 471  0 return true;
 472    }
 473    else
 474  0 return false;
 475    }
 476    }
 477   
 478  6 public boolean removeChild(Fqn fqn)
 479    {
 480  6 return cache.removeNode(new Fqn(getFqn(), fqn));
 481    }
 482   
 483  0 public int dataSize()
 484    {
 485  0 return cache.getKeys(getFqn()).size();
 486    }
 487   
 488  2 public boolean removeChild(Object childName)
 489    {
 490  2 return removeChild(new Fqn(getFqn(), childName));
 491    }
 492   
 493  102259 public boolean removeChildDirect(Object childName)
 494    {
 495  102259 return children != null && children.remove(childName) != null;
 496    }
 497   
 498  4 public boolean removeChildDirect(Fqn f)
 499    {
 500  4 if (f.size() == 1)
 501    {
 502  2 return removeChildDirect(f.getLastElement());
 503    }
 504    else
 505    {
 506  2 NodeSPI child = getChildDirect(f);
 507  2 return child != null && child.getParent().removeChildDirect(f.getLastElement());
 508    }
 509    }
 510   
 511  1437737 public Map<Object, Node<K, V>> getChildrenMapDirect()
 512    {
 513  1437737 return children;
 514    }
 515   
 516  0 public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
 517    {
 518  0 this.children().clear();
 519  0 this.children.putAll(children);
 520    }
 521   
 522  2275 public void putAll(Map data)
 523    {
 524  2275 cache.put(fqn, data);
 525    }
 526   
 527  2 public void replaceAll(Map data)
 528    {
 529  2 cache.put(fqn, data, true);
 530    }
 531   
 532  16280 public void putAllDirect(Map<K, V> data)
 533    {
 534  4343 if (data == null) return;
 535  11937 this.data.putAll(data);
 536    }
 537   
 538  3539 public void removeChildrenDirect()
 539    {
 540  3547 if (children != null)
 541    {
 542  2228 children.clear();
 543    }
 544  3547 children = null;
 545    }
 546   
 547  7576 public void print(StringBuffer sb, int indent)
 548    {
 549  7576 printIndent(sb, indent);
 550  7576 sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
 551  7576 if (children != null)
 552    {
 553  4491 for (Node node : children.values())
 554    {
 555  6003 sb.append("\n");
 556  6003 ((NodeSPI) node).print(sb, indent + INDENT);
 557    }
 558    }
 559    }
 560   
 561    // versioning
 562   
 563  0 public void setVersion(DataVersion version)
 564    {
 565  0 throw new UnsupportedOperationException("Versioning not supported");
 566    }
 567   
 568  0 public DataVersion getVersion()
 569    {
 570  0 throw new UnsupportedOperationException("Versioning not supported");
 571    }
 572   
 573  7921 private void printIndent(StringBuffer sb, int indent)
 574    {
 575  7921 if (sb != null)
 576    {
 577  7921 for (int i = 0; i < indent; i++)
 578    {
 579  64572 sb.append(" ");
 580    }
 581    }
 582    }
 583   
 584  10822 public void addChild(Object child_name, Node<K, V> n)
 585    {
 586  10822 if (child_name != null)
 587    {
 588  10822 children().put(child_name, n);
 589    }
 590    }
 591   
 592    /**
 593    * Returns the name of this node.
 594    */
 595  7921 private Object getName()
 596    {
 597  7921 return fqn.getLastElement();
 598    }
 599   
 600    /**
 601    * Returns the name of this node.
 602    */
 603  11098336 public Fqn getFqn()
 604    {
 605  11098332 return fqn;
 606    }
 607   
 608  73 public void setFqn(Fqn fqn)
 609    {
 610  73 if (log.isTraceEnabled())
 611    {
 612  0 log.trace(getFqn() + " set FQN " + fqn);
 613    }
 614  73 this.fqn = fqn;
 615   
 616  73 if (children == null)
 617    {
 618  53 return;
 619    }
 620   
 621    // process children
 622  20 for (Map.Entry<Object, ? extends Node> me : children.entrySet())
 623    {
 624  20 NodeSPI n = (NodeSPI) me.getValue();
 625  20 Fqn cfqn = new Fqn(fqn, me.getKey());
 626  20 n.setFqn(cfqn);
 627    }
 628    }
 629   
 630  48 public Node<K, V> getChild(Object childName)
 631    {
 632  48 return cache.get(new Fqn(getFqn(), childName));
 633    }
 634   
 635  24940529 public NodeSPI<K, V> getChildDirect(Object childName)
 636    {
 637  0 if (childName == null) return null;
 638  24940522 return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
 639    }
 640   
 641  22717 public Set<Node<K, V>> getChildren()
 642    {
 643  0 if (cache == null) return Collections.emptySet();
 644  22717 Set<Node<K, V>> children = new HashSet<Node<K, V>>();
 645  22717 for (Object c : cache.getChildrenNames(getFqn()))
 646    {
 647  52269 Node n = cache.get(new Fqn(getFqn(), c));
 648  46893 if (n != null) children.add(n);
 649    }
 650  22717 return Collections.unmodifiableSet(children);
 651    }
 652   
 653  339602 public Set<NodeSPI<K, V>> getChildrenDirect()
 654    {
 655    // strip out deleted child nodes...
 656  327466 if (children == null || children.size() == 0) return Collections.emptySet();
 657   
 658  12136 Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
 659  12136 for (Node n : children.values())
 660    {
 661  316707 NodeSPI spi = (NodeSPI) n;
 662  313742 if (!spi.isDeleted()) exclDeleted.add(spi);
 663    }
 664  12136 return Collections.unmodifiableSet(exclDeleted);
 665    }
 666   
 667  87903 public boolean hasChildrenDirect()
 668    {
 669  87903 return children != null && children.size() != 0;
 670    }
 671   
 672  223629 public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
 673    {
 674  223629 if (includeMarkedForRemoval)
 675    {
 676  223621 if (children != null && !children.isEmpty())
 677    {
 678  896 return Collections.unmodifiableSet(new HashSet(children.values()));
 679    }
 680    else
 681    {
 682  222725 return Collections.emptySet();
 683    }
 684    }
 685    else
 686    {
 687  8 return getChildrenDirect();
 688    }
 689    }
 690   
 691    /**
 692    * Adds details of the node into a map as strings.
 693    */
 694  345 private void printDetailsInMap(StringBuffer sb, int indent)
 695    {
 696  345 printIndent(sb, indent);
 697  345 indent += 2;// increse it
 698  345 if (!(getFqn()).isRoot())
 699    {
 700  277 sb.append(Fqn.SEPARATOR);
 701    }
 702  345 sb.append(getName());
 703  345 sb.append(" ");
 704  345 sb.append(data);
 705  345 if (children != null)
 706    {
 707  262 for (Node n : children.values())
 708    {
 709  277 sb.append("\n");
 710  277 ((NodeSPI) n).printDetails(sb, indent);
 711    }
 712    }
 713    }
 714   
 715    /**
 716    * Returns true if the data was loaded from the cache loader.
 717    */
 718  721962 public boolean getDataLoaded()
 719    {
 720  721962 return dataLoaded;
 721    }
 722   
 723    /**
 724    * Sets if the data was loaded from the cache loader.
 725    */
 726  126841 public void setDataLoaded(boolean dataLoaded)
 727    {
 728  126841 this.dataLoaded = dataLoaded;
 729    }
 730    }