Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 375   Methods: 42
NCLOC: 293   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
WorkspaceNodeImpl.java 39.5% 62% 69% 59%
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.optimistic;
 8   
 9    import org.apache.commons.logging.Log;
 10    import org.apache.commons.logging.LogFactory;
 11    import org.jboss.cache.AbstractNode;
 12    import org.jboss.cache.CacheSPI;
 13    import org.jboss.cache.Fqn;
 14    import org.jboss.cache.Node;
 15    import org.jboss.cache.NodeSPI;
 16    import org.jboss.cache.VersionedNode;
 17    import org.jboss.cache.transaction.GlobalTransaction;
 18   
 19    import java.util.ArrayList;
 20    import java.util.Collections;
 21    import java.util.HashMap;
 22    import java.util.HashSet;
 23    import java.util.List;
 24    import java.util.Map;
 25    import java.util.Set;
 26   
 27    /**
 28    * Wraps an ordinary {@link Node} and adds versioning and other meta data to it.
 29    *
 30    * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
 31    * @author Steve Woodcock (<a href="mailto:stevew@jofti.com">stevew@jofti.com</a>)
 32    */
 33    public class WorkspaceNodeImpl<K, V> extends AbstractNode<K, V> implements WorkspaceNode<K, V>
 34    {
 35   
 36    private static Log log = LogFactory.getLog(WorkspaceNodeImpl.class);
 37   
 38    private NodeSPI<K, V> node;
 39    private TransactionWorkspace workspace;
 40    private DataVersion version = DefaultDataVersion.ZERO;
 41    private boolean dirty;
 42    private boolean created;
 43    private boolean childrenModified;
 44    private Map<Object, NodeSPI<K, V>> optimisticChildNodeMap;
 45    private Set<Fqn> childrenAdded = new HashSet<Fqn>();
 46    private Set<Fqn> childrenRemoved = new HashSet<Fqn>();
 47    private Map<K, V> optimisticDataMap;
 48    private boolean versioningImplicit = true; // default
 49   
 50    /**
 51    * Constructs with a node and workspace.
 52    */
 53  1053958 public WorkspaceNodeImpl(NodeSPI<K, V> node, TransactionWorkspace workspace)
 54    {
 55  1053958 if (!(node instanceof VersionedNode))
 56    {
 57  0 throw new IllegalArgumentException("node " + node + " not VersionedNode");
 58    }
 59  1053958 this.node = node;
 60  1053958 this.workspace = workspace;
 61  1053958 optimisticDataMap = new HashMap<K, V>(node.getDataDirect());
 62  1053958 Map<Object, Node<K, V>> childrenMap = node.getChildrenMapDirect();
 63    // we NEED this null check otherwise the ConcurrentHashMap constructor could throw an NPE
 64    // could this not be a HashMap? After all, each WNI is only used within a single Workspace, which is only
 65    // attached to a single transaction entry.
 66  1053958 this.optimisticChildNodeMap = childrenMap == null ? new HashMap() : new HashMap(childrenMap);
 67    // optimisticChildNodeMap = new HashMap(childrenMap);
 68  1053958 this.version = node.getVersion();
 69  1053958 if (version == null)
 70    {
 71  0 throw new IllegalStateException("VersionedNode version null");
 72    }
 73    }
 74   
 75  1053159 public boolean isChildrenModified()
 76    {
 77  1053159 return childrenModified;
 78    }
 79   
 80    /**
 81    * Returns true if this node is dirty.
 82    */
 83  1054860 public boolean isDirty()
 84    {
 85  1054860 return dirty;
 86    }
 87   
 88  2116086 public Fqn getFqn()
 89    {
 90  2116086 return node.getFqn();
 91    }
 92   
 93  275 public void putAll(Map<K, V> data)
 94    {
 95  275 realPut(data, false);
 96  275 dirty = true;
 97    }
 98   
 99  0 public void replaceAll(Map<K, V> data)
 100    {
 101  0 clearData();
 102  0 putAll(data);
 103    }
 104   
 105  1431 public V put(K key, V value)
 106    {
 107  1431 dirty = true;
 108  1431 return optimisticDataMap.put(key, value);
 109   
 110    }
 111   
 112  20 public V remove(K key)
 113    {
 114  20 dirty = true;
 115  20 return optimisticDataMap.remove(key);
 116   
 117    }
 118   
 119  1049917 public V get(K key)
 120    {
 121  1049917 return optimisticDataMap.get(key);
 122    }
 123   
 124  34 public Set<K> getKeys()
 125    {
 126  34 return optimisticDataMap.keySet();
 127    }
 128   
 129    //not able to delete from this
 130  320 public Set<Object> getChildrenNames()
 131    {
 132  320 return new HashSet<Object>(optimisticChildNodeMap.keySet());
 133    }
 134   
 135  275 private void realPut(Map<K, V> data, boolean eraseData)
 136    {
 137  275 realPut(data, eraseData, true);
 138    }
 139   
 140  275 private void realPut(Map<K, V> data, boolean eraseData, boolean forceDirtyFlag)
 141    {
 142  275 if (forceDirtyFlag) dirty = true;
 143  275 if (eraseData)
 144    {
 145  0 optimisticDataMap.clear();
 146    }
 147  164 if (data != null) optimisticDataMap.putAll(data);
 148    }
 149   
 150  0 public Node<K, V> getParent()
 151    {
 152  0 return node.getParent();
 153    }
 154   
 155  1403 public NodeSPI<K, V> createChild(Object child_name, NodeSPI<K, V> parent, CacheSPI<K, V> cache, DataVersion version)
 156    {
 157  1403 if (child_name == null)
 158    {
 159  0 return null;
 160    }
 161   
 162    //see if we already have it
 163  1403 NodeSPI child = optimisticChildNodeMap.get(child_name);
 164   
 165    // if not we need to create it
 166  1403 if (child == null)
 167    {
 168  1403 child = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNodeOfType(parent, child_name, parent, null);
 169  1403 optimisticChildNodeMap.put(child_name, child);
 170  1403 childrenAdded.add(child.getFqn());
 171  1403 childrenRemoved.remove(child.getFqn());
 172    }
 173  1403 childrenModified = true;
 174  1403 return child;
 175    }
 176   
 177  1415 public boolean isVersioningImplicit()
 178    {
 179  1415 return versioningImplicit;
 180    }
 181   
 182  3833 public void setVersioningImplicit(boolean b)
 183    {
 184  3833 versioningImplicit = b;
 185    }
 186   
 187  4927 public NodeSPI<K, V> getChild(Object childName)
 188    {
 189    //see if in the the transaction map
 190  4927 return optimisticChildNodeMap.get(childName);
 191    }
 192   
 193  1058793 public NodeSPI<K, V> getNode()
 194    {
 195  1058793 return node;
 196    }
 197   
 198  1055499 public DataVersion getVersion()
 199    {
 200  1055499 return version;
 201    }
 202   
 203  222 public void setVersion(DataVersion version)
 204    {
 205  222 this.version = version;
 206    }
 207   
 208  1092 public List<Set<Fqn>> getMergedChildren()
 209    {
 210    //return optimisticChildNodeMap;
 211  1092 List<Set<Fqn>> l = new ArrayList<Set<Fqn>>(2);
 212  1092 l.add(childrenAdded);
 213  1092 l.add(childrenRemoved);
 214  1092 return l;
 215    }
 216   
 217  1224 public Map<K, V> getMergedData()
 218    {
 219  1224 return optimisticDataMap;
 220    }
 221   
 222  0 public TransactionWorkspace getTransactionWorkspace()
 223    {
 224  0 return workspace;
 225    }
 226   
 227  5698 public boolean isCreated()
 228    {
 229  5698 return created;
 230    }
 231   
 232  1403 public void markAsCreated()
 233    {
 234  1403 created = true;
 235    // created != dirty!!!
 236    // dirty = true;
 237    }
 238   
 239  2122 public Map<K, V> getData()
 240    {
 241  2122 return Collections.unmodifiableMap(optimisticDataMap);
 242    }
 243   
 244  0 public String toString()
 245    {
 246  0 StringBuffer sb = new StringBuffer();
 247  0 if (deleted) sb.append("del ");
 248  0 if (dirty) sb.append("dirty ");
 249  0 if (created) sb.append("new ");
 250  0 return getClass().getSimpleName() + " [ fqn=" + getFqn() + " " + sb + "ver=" + version + " " + (versioningImplicit ? "implicit" : "explicit") + "]";
 251    }
 252   
 253  0 public Node<K, V> addChild(Fqn f)
 254    {
 255  0 CacheSPI cache = getCache();
 256  0 Node newNode = this;
 257  0 GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
 258   
 259  0 if (f.size() == 1)
 260    {
 261  0 newNode = createChild(f.get(0), node, getCache(), version);
 262    }
 263    else
 264    {
 265    // recursively create children
 266  0 Node currentParent = this;
 267  0 for (Object o : f.peekElements())
 268    {
 269  0 if (currentParent instanceof WorkspaceNode)
 270    {
 271  0 newNode = ((WorkspaceNode) currentParent).getNode().getOrCreateChild(o, gtx);
 272    }
 273    else
 274    {
 275  0 if (currentParent instanceof WorkspaceNode)
 276    {
 277  0 newNode = ((WorkspaceNode) currentParent).getNode().getOrCreateChild(o, gtx);
 278    }
 279    else
 280    {
 281  0 newNode = ((NodeSPI) currentParent).getOrCreateChild(o, gtx);
 282    }
 283    }
 284  0 currentParent = newNode;
 285    }
 286    }
 287  0 return newNode;
 288    }
 289   
 290  12 public void addChild(WorkspaceNode child)
 291    {
 292  12 optimisticChildNodeMap.put(child.getFqn().getLastElement(), child.getNode());
 293  12 childrenAdded.add(child.getFqn());
 294  12 childrenRemoved.remove(child.getFqn());
 295  0 if (log.isTraceEnabled()) log.trace("Adding child " + child.getFqn());
 296    }
 297   
 298  11 public void clearData()
 299    {
 300  11 dirty = true;
 301  11 optimisticDataMap.clear();
 302    }
 303   
 304  0 public int dataSize()
 305    {
 306  0 return optimisticDataMap.size();
 307    }
 308   
 309  17 public NodeSPI<K, V> getChild(Fqn f)
 310    {
 311  17 if (f.size() > 1)
 312    {
 313  0 throw new UnsupportedOperationException("Workspace node does not support fetching indirect children");
 314    }
 315  17 return getChild(f.getLastElement());
 316    }
 317   
 318  0 public Set<Node<K, V>> getChildren()
 319    {
 320  0 throw new UnsupportedOperationException();
 321    }
 322   
 323  0 public boolean hasChild(Fqn f)
 324    {
 325  0 throw new UnsupportedOperationException();
 326    }
 327   
 328  0 public NodeSPI<K, V> getNodeSPI()
 329    {
 330  0 throw new UnsupportedOperationException("WorkspaceNode has no access to a NodeSPI");
 331    }
 332   
 333  0 public V putIfAbsent(K k, V v)
 334    {
 335  0 throw new UnsupportedOperationException();
 336    }
 337   
 338  0 public V replace(K key, V value)
 339    {
 340  0 throw new UnsupportedOperationException();
 341    }
 342   
 343  0 public boolean replace(K key, V oldValue, V newValue)
 344    {
 345  0 throw new UnsupportedOperationException();
 346    }
 347   
 348  28 public boolean removeChild(Fqn f)
 349    {
 350  0 if (f.size() > 1) throw new UnsupportedOperationException("Workspace nodes can only remove direct children!");
 351  28 Object key = f.getLastElement();
 352  28 return removeChild(key);
 353    }
 354   
 355  206 public boolean removeChild(Object childName)
 356    {
 357  206 NodeSPI n = optimisticChildNodeMap.remove(childName);
 358  206 if (n != null)
 359    {
 360  178 childrenRemoved.add(n.getFqn());
 361  178 childrenAdded.remove(n.getFqn());
 362  178 childrenModified = true;
 363  178 return true;
 364    }
 365    else
 366    {
 367  28 return false;
 368    }
 369    }
 370   
 371  0 protected CacheSPI<K, V> getCache()
 372    {
 373  0 return node.getCache();
 374    }
 375    }