Clover coverage report -
Coverage timestamp: Thu Jul 5 2007 20:02:32 EDT
file stats: LOC: 246   Methods: 4
NCLOC: 162   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
OptimisticCreateIfNotExistsInterceptor.java 62.1% 80.9% 100% 74.4%
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.interceptors;
 8   
 9    import org.jboss.cache.CacheException;
 10    import org.jboss.cache.CacheSPI;
 11    import org.jboss.cache.Fqn;
 12    import org.jboss.cache.InvocationContext;
 13    import org.jboss.cache.NodeFactory;
 14    import org.jboss.cache.NodeSPI;
 15    import org.jboss.cache.marshall.MethodCall;
 16    import org.jboss.cache.marshall.MethodDeclarations;
 17    import org.jboss.cache.notifications.Notifier;
 18    import org.jboss.cache.optimistic.DataVersion;
 19    import org.jboss.cache.optimistic.DefaultDataVersion;
 20    import org.jboss.cache.optimistic.TransactionWorkspace;
 21    import org.jboss.cache.optimistic.WorkspaceNode;
 22    import org.jboss.cache.transaction.GlobalTransaction;
 23   
 24    import java.util.ArrayList;
 25    import java.util.List;
 26   
 27    /**
 28    * Used to create new {@link NodeSPI} instances in the main data structure and then copy it into the
 29    * {@link TransactionWorkspace} as {@link WorkspaceNode}s as needed. This is only invoked if nodes needed do not exist
 30    * in the underlying structure, they are added and the corresponding {@link org.jboss.cache.optimistic.WorkspaceNode#isCreated()}
 31    * would return <tt>true</tt> to denote that this node has been freshly created in the underlying structure.
 32    *
 33    * @author <a href="mailto:manik@jboss.org">Manik Surtani (manik@jboss.org)</a>
 34    * @author <a href="mailto:stevew@jofti.com">Steve Woodcock (stevew@jofti.com)</a>
 35    */
 36    public class OptimisticCreateIfNotExistsInterceptor extends OptimisticInterceptor
 37    {
 38    /**
 39    * A reference to the node factory registered with the cache instance, used to create both WorkspaceNodes as well as
 40    * NodeSPI objects in the underlying data structure.
 41    */
 42    private NodeFactory nodeFactory;
 43   
 44  912 public void setCache(CacheSPI cache)
 45    {
 46  912 super.setCache(cache);
 47    // set a reference to the node factory
 48  912 nodeFactory = cache.getConfiguration().getRuntimeConfig().getNodeFactory();
 49    }
 50   
 51  1055021 public Object invoke(InvocationContext ctx) throws Throwable
 52    {
 53  1055021 MethodCall m = ctx.getMethodCall();
 54  1055021 if (MethodDeclarations.isPutMethod(m.getMethodId()))
 55    {
 56  2074 Object[] args = m.getArgs();
 57  2074 Fqn fqn = (Fqn) (args != null ? args[1] : null);
 58   
 59  2074 if (cache.peek(fqn, false) == null)
 60    {
 61  1601 createNode(ctx, fqn, false);
 62    }
 63    }
 64  1052947 else if (m.getMethodId() == MethodDeclarations.moveMethodLocal_id)
 65    {
 66  28 Object[] args = m.getArgs();
 67  28 move(ctx, (Fqn) args[0], (Fqn) args[1]);
 68    }
 69   
 70  1055019 return super.invoke(ctx);
 71    }
 72   
 73  28 private void move(InvocationContext ctx, Fqn nodeFqn, Fqn newParent)
 74    {
 75  28 List<Fqn> fqns = new ArrayList<Fqn>();
 76  28 fqns.add(newParent);
 77   
 78    // peek into Node and get a hold of all child fqns as these need to be in the workspace.
 79  28 NodeSPI node = cache.peek(nodeFqn, true);
 80  28 greedyGetFqns(fqns, node, newParent);
 81   
 82   
 83  0 if (trace) log.trace("Adding Fqns " + fqns + " for a move() operation.");
 84   
 85   
 86  28 for (Fqn f : fqns)
 87    {
 88  38 if (cache.peek(f, false) == null) createNode(ctx, f, true);
 89    }
 90    }
 91   
 92    /**
 93    * The only method that should be creating nodes.
 94    *
 95    * @param targetFqn
 96    * @throws CacheException
 97    */
 98  1639 private void createNode(InvocationContext ctx, Fqn targetFqn, boolean suppressNotification) throws CacheException
 99    {
 100    // we do nothing if targetFqn is null
 101  0 if (targetFqn == null) return;
 102   
 103  1639 boolean debug = log.isDebugEnabled();
 104   
 105  1639 GlobalTransaction gtx = getGlobalTransaction(ctx);
 106  1637 TransactionWorkspace workspace = getTransactionWorkspace(gtx);
 107   
 108  1637 WorkspaceNode workspaceNode;
 109   
 110  1637 List<Fqn> nodesCreated = new ArrayList<Fqn>();
 111   
 112    // synchronize on the workspace so that more than one thread doesn't attempt to put stuff into the workspace for
 113    // the same transaction.
 114  1637 synchronized (workspace)
 115    {
 116  1637 DataVersion version = null;
 117  1637 if (ctx.getOptionOverrides() != null && ctx.getOptionOverrides().getDataVersion() != null)
 118    {
 119  149 version = ctx.getOptionOverrides().getDataVersion();
 120  149 workspace.setVersioningImplicit(false);
 121    }
 122   
 123    // start with the ROOT node and then work our way down to the node necessary, creating nodes along the way.
 124  1637 workspaceNode = workspace.getNode(Fqn.ROOT);
 125  0 if (debug) log.debug("GlobalTransaction: " + gtx + "; Root: " + workspaceNode);
 126   
 127    // we do not have the root in the workspace! Put it into thr workspace now.
 128  1637 if (workspaceNode == null)
 129    {
 130  896 NodeSPI node = cache.getRoot();
 131  896 workspaceNode = nodeFactory.createWorkspaceNode(node, workspace);
 132  896 workspace.addNode(workspaceNode);
 133  896 log.debug("Created root node in workspace.");
 134    }
 135    else
 136    {
 137  741 log.debug("Found root node in workspace.");
 138    }
 139   
 140    // we will always have one root node here, by this stage
 141  1637 Fqn currentFqn = Fqn.ROOT;
 142   
 143    // iterate through the target Fqn's elements.
 144  1637 int targetFqnSize = targetFqn.size(), currentDepth = 1;
 145  1637 for (Object childName : targetFqn.peekElements())
 146    {
 147  3892 boolean isTargetFqn = (currentDepth == targetFqnSize);
 148  3892 currentDepth++;
 149   
 150    // current workspace node canot be null.
 151    // try and get the child of current node
 152   
 153  0 if (debug) log.debug("Attempting to get child " + childName);
 154  3892 NodeSPI currentNode = workspaceNode.getChild(childName);
 155   
 156   
 157  3892 if (currentNode == null)
 158    {
 159    // no child exists with this name; create it in the underlying data structure and then add it to the workspace.
 160  0 if (trace) log.trace("Creating new child, since it doesn't exist in the cache.");
 161    // we put the parent node into the workspace as we are changing it's children.
 162    // at this point "workspaceNode" refers to the parent of the current node. It should never be null if
 163    // you got this far!
 164  1403 if (workspaceNode.isDeleted())
 165    {
 166    //add a new one or overwrite an existing one that has been deleted
 167  0 if (trace)
 168  0 log.trace("Parent node doesn't exist in workspace or has been deleted. Adding to workspace.");
 169  0 workspace.addNode(workspaceNode);
 170  0 if (!(workspaceNode.getVersion() instanceof DefaultDataVersion))
 171  0 workspaceNode.setVersioningImplicit(false);
 172    }
 173    else
 174    {
 175  0 if (trace) log.trace("Parent node exists: " + workspaceNode);
 176    }
 177   
 178    // get the version passed in, if we need to use explicit versioning.
 179  1403 DataVersion versionToPassIn = null;
 180  129 if (isTargetFqn && !workspace.isVersioningImplicit()) versionToPassIn = version;
 181   
 182  1403 NodeSPI newUnderlyingChildNode = workspaceNode.createChild(childName, workspaceNode.getNode(), cache, versionToPassIn);
 183   
 184    // now assign "workspaceNode" to the new child created.
 185  1403 workspaceNode = nodeFactory.createWorkspaceNode(newUnderlyingChildNode, workspace);
 186  1403 workspaceNode.setVersioningImplicit(versionToPassIn == null || !isTargetFqn);
 187  1403 if (trace)
 188  0 log.trace("setting versioning of " + workspaceNode.getFqn() + " to be " + (workspaceNode.isVersioningImplicit() ? "implicit" : "explicit"));
 189   
 190    // now add the wrapped child node into the transaction space
 191  1403 workspace.addNode(workspaceNode);
 192  1403 workspaceNode.markAsCreated();
 193    // save in list so we can broadcast our created nodes outside
 194    // the synch block
 195  1403 nodesCreated.add(workspaceNode.getFqn());
 196    }
 197    else
 198    {
 199    // node does exist but might not be in the workspace
 200  2489 workspaceNode = workspace.getNode(currentNode.getFqn());
 201    // wrap it up so we can put it in later if we need to
 202  2489 if (workspaceNode == null || workspaceNode.isDeleted())
 203    {
 204  510 if (trace)
 205  0 log.trace("Child node " + currentNode.getFqn() + " doesn't exist in workspace or has been deleted. Adding to workspace in gtx " + gtx);
 206   
 207  510 workspaceNode = nodeFactory.createWorkspaceNode(currentNode, workspace);
 208  510 if (isTargetFqn && !workspace.isVersioningImplicit())
 209    {
 210  0 workspaceNode.setVersion(version);
 211  0 workspaceNode.setVersioningImplicit(false);
 212    }
 213    else
 214    {
 215  510 workspaceNode.setVersioningImplicit(true);
 216    }
 217  510 if (trace)
 218  0 log.trace("setting versioning of " + workspaceNode.getFqn() + " to be " + (workspaceNode.isVersioningImplicit() ? "implicit" : "explicit"));
 219  510 workspace.addNode(workspaceNode);
 220    }
 221    else
 222    {
 223  0 if (trace) log.trace("Found child node in the workspace: " + currentNode);
 224   
 225    }
 226    }
 227    }
 228   
 229    }// end sync block
 230   
 231  1637 if (!suppressNotification)
 232    {
 233  1599 if (nodesCreated.size() > 0)
 234    {
 235  1088 Notifier n = cache.getNotifier();
 236  1088 for (Fqn temp : nodesCreated)
 237    {
 238  1365 n.notifyNodeCreated(temp, true, ctx);
 239  1365 n.notifyNodeCreated(temp, false, ctx);
 240  0 if (trace) log.trace("Notifying cache of node created in workspace " + temp);
 241    }
 242    }
 243    }
 244    }
 245   
 246    }