1 7 package org.jboss.cache.interceptors; 8 9 import org.jboss.cache.CacheException; 10 import org.jboss.cache.CacheListener; 11 import org.jboss.cache.CacheSPI; 12 import org.jboss.cache.Fqn; 13 import org.jboss.cache.GlobalTransaction; 14 import org.jboss.cache.InvocationContext; 15 import org.jboss.cache.NodeNotExistsException; 16 import org.jboss.cache.NodeSPI; 17 import org.jboss.cache.config.Option; 18 import org.jboss.cache.factories.NodeFactory; 19 import org.jboss.cache.marshall.MethodCall; 20 import org.jboss.cache.marshall.MethodDeclarations; 21 import org.jboss.cache.optimistic.DataVersion; 22 import org.jboss.cache.optimistic.TransactionWorkspace; 23 import org.jboss.cache.optimistic.WorkspaceNode; 24 25 import java.util.HashMap ; 26 import java.util.Iterator ; 27 import java.util.Map ; 28 import java.util.SortedMap ; 29 30 36 public class OptimisticNodeInterceptor extends OptimisticInterceptor 37 { 38 private NodeFactory nodeFactory; 39 40 public void setCache(CacheSPI c) 41 { 42 super.setCache(c); 43 nodeFactory = c.getConfiguration().getRuntimeConfig().getNodeFactory(); 44 } 45 46 public Object invoke(MethodCall m) throws Throwable 47 { 48 if (MethodDeclarations.isBuddyGroupOrganisationMethod(m.getMethodId())) return super.invoke(m); 50 51 if (log.isTraceEnabled()) log.trace("Processing method call " + m); 52 53 InvocationContext ctx = cache.getInvocationContext(); 54 Object [] args = m.getArgs(); 55 56 Object result = null; 57 58 GlobalTransaction gtx = ctx.getGlobalTransaction(); 59 60 TransactionWorkspace workspace = getTransactionWorkspace(gtx); 61 62 if (MethodDeclarations.moveMethodLocal_id == m.getMethodId()) 63 { 64 if (ctx.getOptionOverrides().getDataVersion() != null && ctx.isOriginLocal()) 65 { 66 throw new CacheException("Setting a data version while performing a move() is not supported!!"); 67 } 68 69 Fqn parentFqn = (Fqn) args[1], nodeFqn = (Fqn) args[0]; 70 71 if (log.isTraceEnabled()) 72 { 73 log.trace("Adding nodes " + parentFqn + " and " + nodeFqn + " to the workspace."); 74 } 75 76 WorkspaceNode parent = getOrCreateWorkspaceNode(parentFqn, workspace, false); 77 if (parent == null) throw new NodeNotExistsException("Node " + parentFqn + " does not exist!"); 78 WorkspaceNode node = getOrCreateWorkspaceNode(nodeFqn, workspace, true); 79 80 if (log.isTraceEnabled()) log.trace("Parent: " + parent); 81 if (log.isTraceEnabled()) log.trace("Node: " + node); 82 83 if (log.isTraceEnabled()) log.trace("Workspace snapshot: " + workspace); 84 85 greedyGetNodes(node, workspace); 87 88 90 doMove(parent, node, workspace); 91 92 addToModificationList(gtx, m); 93 } 94 else if (MethodDeclarations.isCrudMethod(m.getMethodId())) 95 { 96 Fqn fqn = getFqn(args); 99 WorkspaceNode workspaceNode = getOrCreateWorkspaceNode(fqn, workspace, true); 100 101 102 if (workspaceNode != null) 103 { 104 if (ctx.getOptionOverrides() != null && ctx.getOptionOverrides().getDataVersion() != null) 106 { 107 workspace.setVersioningImplicit(false); 108 DataVersion version = ctx.getOptionOverrides().getDataVersion(); 109 110 workspaceNode.setVersion(version); 111 if (log.isTraceEnabled()) 112 { 113 log.trace("Setting versioning for node " + workspaceNode.getFqn() + " to explicit"); 114 } 115 workspaceNode.setVersioningImplicit(false); 116 } 117 else 118 { 119 if (log.isTraceEnabled()) 120 { 121 log.trace("Setting versioning for node " + workspaceNode.getFqn() + " to implicit"); 122 } 123 workspaceNode.setVersioningImplicit(true); 124 } 125 } 126 else 127 { 128 if ((ctx.getOptionOverrides() == null || !ctx.getOptionOverrides().isFailSilently()) && MethodDeclarations.isPutMethod(m.getMethodId())) 130 { 131 throw new CacheException("Unable to set node version for " + getFqn(args) + ", node is null."); 132 } 133 } 134 135 switch (m.getMethodId()) 136 { 137 case MethodDeclarations.putDataMethodLocal_id: 138 Boolean erase = (Boolean ) args[3]; 139 cache.getNotifier().notifyNodeModified(fqn, true, CacheListener.ModificationType.PUT_MAP, workspaceNode == null ? null : workspaceNode.getData(), false); 140 putDataMap((Map <Object , Object >) args[2], erase, workspace, workspaceNode); 141 cache.getNotifier().notifyNodeModified(fqn, false, CacheListener.ModificationType.PUT_MAP, workspaceNode.getData(), false); 142 break; 143 case MethodDeclarations.putDataEraseMethodLocal_id: 144 cache.getNotifier().notifyNodeModified(fqn, true, CacheListener.ModificationType.PUT_MAP, workspaceNode == null ? null : workspaceNode.getData(), false); 145 putDataMap((Map <Object , Object >) args[2], true, workspace, workspaceNode); 146 cache.getNotifier().notifyNodeModified(fqn, false, CacheListener.ModificationType.PUT_MAP, workspaceNode.getData(), false); 147 break; 148 case MethodDeclarations.putKeyValMethodLocal_id: 149 Object key = args[2]; 150 Object value = args[3]; 151 Map addedData = new HashMap (); 152 addedData.put(key, value); 153 154 cache.getNotifier().notifyNodeModified(fqn, true, CacheListener.ModificationType.PUT_DATA, workspaceNode == null ? null : workspaceNode.getData(), false); 155 result = putDataKeyValue(key, value, workspace, workspaceNode); 156 cache.getNotifier().notifyNodeModified(fqn, false, CacheListener.ModificationType.PUT_DATA, addedData, false); 157 break; 158 case MethodDeclarations.removeNodeMethodLocal_id: 159 cache.getNotifier().notifyNodeRemoved(fqn, true, workspaceNode == null ? null : workspaceNode.getData(), false); 160 removeNode(workspace, workspaceNode); 161 cache.getNotifier().notifyNodeRemoved(fqn, false, null, false); 162 break; 163 case MethodDeclarations.removeKeyMethodLocal_id: 164 cache.getNotifier().notifyNodeModified(fqn, true, CacheListener.ModificationType.REMOVE_DATA, workspaceNode == null ? null : workspaceNode.getData(), false); 165 Object removeKey = args[2]; 166 result = removeKey(removeKey, workspace, workspaceNode); 167 Map removedData = new HashMap (); 168 removedData.put(removeKey, result); 169 cache.getNotifier().notifyNodeModified(fqn, false, CacheListener.ModificationType.REMOVE_DATA, removedData, false); 170 break; 171 case MethodDeclarations.removeDataMethodLocal_id: 172 Map data = workspaceNode == null ? null : new HashMap (workspaceNode.getData()); 173 cache.getNotifier().notifyNodeModified(fqn, true, CacheListener.ModificationType.REMOVE_DATA, data, false); 174 removeData(workspace, workspaceNode); 175 cache.getNotifier().notifyNodeModified(fqn, false, CacheListener.ModificationType.REMOVE_DATA, data, false); 176 break; 177 case MethodDeclarations.dataGravitationCleanupMethod_id: 178 result = super.invoke(m); 179 default: 180 if (log.isInfoEnabled()) log.info("Cannot Handle Method " + m); 181 break; 182 } 183 184 addToModificationList(gtx, m); 185 } 186 else 187 { 188 switch (m.getMethodId()) 189 { 190 case MethodDeclarations.getKeyValueMethodLocal_id: 191 result = getValueForKey(args, workspace); 192 break; 193 case MethodDeclarations.getKeysMethodLocal_id: 194 result = getKeys(args, workspace); 195 break; 196 case MethodDeclarations.getChildrenNamesMethodLocal_id: 197 result = getChildNames(args, workspace); 198 break; 199 case MethodDeclarations.getNodeMethodLocal_id: 200 result = getNode(args, workspace); 201 break; 202 default: 203 if (log.isInfoEnabled()) 204 { 205 log.info("read Method " + m + " called - don't know how to handle, passing on!"); 206 } 207 result = super.invoke(m); 208 break; 209 } 210 } 211 return result; 212 } 213 214 private void addToModificationList(GlobalTransaction gtx, MethodCall m) 215 { 216 Option opt = cache.getInvocationContext().getOptionOverrides(); 217 if (opt == null || !opt.isCacheModeLocal()) 218 { 219 txTable.addModification(gtx, m); 220 if (log.isDebugEnabled()) log.debug("Adding Method " + m + " to modification list"); 221 } 222 if (cache.getCacheLoaderManager() != null) txTable.addCacheLoaderModification(gtx, m); 223 224 } 225 226 public void doMove(WorkspaceNode parent, WorkspaceNode node, TransactionWorkspace ws) 227 { 228 Fqn nodeFqn = node.getFqn(); 229 if (nodeFqn.isRoot()) 230 { 231 log.warn("Attempting to move the root node. Not taking any action, treating this as a no-op."); 232 return; 233 } 234 WorkspaceNode oldParent = getOrCreateWorkspaceNode(nodeFqn.getParent(), ws, false); 235 if (oldParent == null) throw new NodeNotExistsException("Node " + nodeFqn.getParent() + " does not exist!"); 236 Object nodeName = nodeFqn.getLastElement(); 237 238 oldParent.removeChild(new Fqn(nodeName)); 241 244 246 Fqn nodeNewFqn = new Fqn(parent.getFqn(), nodeFqn.getLastElement()); 249 cache.getNotifier().notifyNodeMoved(nodeFqn, nodeNewFqn, true, false); 250 moveFqns(node, parent.getFqn(), ws); 251 252 removeNode(ws, node); 254 255 cache.getNotifier().notifyNodeMoved(nodeFqn, nodeNewFqn, false, false); 257 } 258 259 262 private void moveFqns(WorkspaceNode node, Fqn newBase, TransactionWorkspace ws) 263 { 264 Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement()); 265 WorkspaceNode movedNode = getOrCreateWorkspaceNode(newFqn, ws, true); 266 movedNode.put(node.getData()); 267 268 for (Object n : node.getChildrenNames()) 270 { 271 WorkspaceNode child = getOrCreateWorkspaceNode(new Fqn(node.getFqn(), n), ws, false); 272 if (child != null) moveFqns(child, newFqn, ws); 273 } 274 } 275 276 281 protected void greedyGetNodes(WorkspaceNode n, TransactionWorkspace ws) 282 { 283 Fqn myFqn = n.getFqn(); 284 285 for (Object child : n.getChildrenNames()) 286 { 287 Fqn childFqn = new Fqn(myFqn, child); 288 WorkspaceNode cn = getOrCreateWorkspaceNode(childFqn, ws, false); 289 if (!ws.hasNode(childFqn)) ws.addNode(cn); 290 greedyGetNodes(cn, ws); 291 } 292 } 293 294 private Fqn getFqn(Object [] args) 295 { 296 return (Fqn) args[1]; 297 } 298 299 private void putDataMap(Map <Object , Object > data, boolean eraseExisitng, 300 TransactionWorkspace workspace, WorkspaceNode workspaceNode) 301 { 302 if (workspaceNode == null) 303 { 304 return; 305 } 306 if (eraseExisitng) workspaceNode.clearData(); 307 workspaceNode.put(data); 308 workspace.addNode(workspaceNode); 309 } 310 311 private Object putDataKeyValue(Object key, Object value, TransactionWorkspace workspace, WorkspaceNode workspaceNode) 312 { 313 if (workspaceNode == null) 314 { 315 return null; } 317 318 Object old = workspaceNode.put(key, value); 319 workspace.addNode(workspaceNode); 320 return old; 321 } 322 323 private void removeNode(TransactionWorkspace workspace, WorkspaceNode workspaceNode) throws CacheException 324 { 325 if (log.isTraceEnabled()) 326 { 327 log.trace("removeNode " + workspace + " node=" + workspaceNode); 328 } 329 330 if (workspaceNode == null) 332 { 333 return; 334 } 335 336 boolean debug = log.isDebugEnabled(); 337 338 Fqn parentFqn = workspaceNode.getFqn().getParent(); 339 WorkspaceNode parentNode = getOrCreateWorkspaceNode(parentFqn, workspace, false); 340 if (parentNode == null) 341 { 342 throw new NodeNotExistsException("Unable to find parent node with Fqn " + parentFqn); 343 } 344 345 parentNode.removeChild(new Fqn(workspaceNode.getFqn().getLastElement())); 346 workspace.addNode(parentNode); 347 if (debug) log.debug("added parent node " + parentNode.getFqn() + " to workspace"); 348 Fqn nodeFqn = workspaceNode.getFqn(); 349 350 workspace.addNode(workspaceNode); SortedMap tailMap = workspace.getNodesAfter(workspaceNode.getFqn()); 353 354 for (Iterator it = tailMap.entrySet().iterator(); it.hasNext();) 355 { 356 WorkspaceNode toDelete = (WorkspaceNode) ((Map.Entry ) it.next()).getValue(); 357 if (toDelete.getFqn().isChildOrEquals(nodeFqn)) 358 { 359 if (debug) log.debug("marking node " + toDelete.getFqn() + " as deleted"); 360 toDelete.markAsDeleted(true); 361 } 362 else 363 { 364 break; } 366 } 367 } 368 369 private Object removeKey(Object removeKey, TransactionWorkspace workspace, WorkspaceNode workspaceNode) 370 { 371 if (workspaceNode == null) 372 { 373 return null; 374 } 375 376 Object old = workspaceNode.remove(removeKey); 377 workspace.addNode(workspaceNode); 378 return old; 379 } 380 381 private void removeData(TransactionWorkspace workspace, WorkspaceNode workspaceNode) 382 { 383 if (workspaceNode == null) 384 { 385 return; 386 } 387 workspaceNode.clearData(); 388 workspace.addNode(workspaceNode); 389 } 390 391 private Object getValueForKey(Object [] args, TransactionWorkspace workspace) 392 { 393 Fqn fqn = (Fqn) args[0]; 394 Object key = args[1]; 395 WorkspaceNode workspaceNode = getOrCreateWorkspaceNode(fqn, workspace, false); 396 397 if (workspaceNode == null) 398 { 399 if (log.isDebugEnabled()) log.debug("unable to find node " + fqn + " in workspace."); 400 return null; 401 } 402 else 403 { 404 cache.getNotifier().notifyNodeVisited(fqn, true, false); 406 Object val = workspaceNode.get(key); 407 workspace.addNode(workspaceNode); 408 cache.getNotifier().notifyNodeVisited(fqn, false, false); 409 return val; 410 } 411 } 412 413 private Object getNode(Object [] args, TransactionWorkspace workspace) 414 { 415 Fqn fqn = (Fqn) args[0]; 416 417 WorkspaceNode workspaceNode = getOrCreateWorkspaceNode(fqn, workspace, false); 418 419 if (workspaceNode == null) 420 { 421 if (log.isDebugEnabled()) log.debug("unable to find node " + fqn + " in workspace."); 422 return null; 423 } 424 else 425 { 426 cache.getNotifier().notifyNodeVisited(fqn, true, false); 427 workspace.addNode(workspaceNode); 428 cache.getNotifier().notifyNodeVisited(fqn, false, false); 429 return workspaceNode.getNode(); 430 } 431 } 432 433 private Object getKeys(Object [] args, TransactionWorkspace workspace) 434 { 435 Fqn fqn = (Fqn) args[0]; 436 437 WorkspaceNode workspaceNode = getOrCreateWorkspaceNode(fqn, workspace, false); 438 439 if (workspaceNode == null) 440 { 441 if (log.isDebugEnabled()) log.debug("unable to find node " + fqn + " in workspace."); 442 return null; 443 } 444 else 445 { 446 cache.getNotifier().notifyNodeVisited(fqn, true, false); 447 Object keySet = workspaceNode.getKeys(); 448 workspace.addNode(workspaceNode); 449 cache.getNotifier().notifyNodeVisited(fqn, false, false); 450 return keySet; 451 } 452 } 453 454 private Object getChildNames(Object [] args, TransactionWorkspace workspace) 455 { 456 Fqn fqn = (Fqn) args[0]; 457 458 WorkspaceNode workspaceNode = getOrCreateWorkspaceNode(fqn, workspace, false); 459 460 if (workspaceNode == null) 461 { 462 if (log.isDebugEnabled()) log.debug("unable to find node " + fqn + " in workspace."); 463 return null; 464 } 465 else 466 { 467 cache.getNotifier().notifyNodeVisited(fqn, true, false); 468 Object nameSet = workspaceNode.getChildrenNames(); 469 workspace.addNode(workspaceNode); 470 cache.getNotifier().notifyNodeVisited(fqn, false, false); 471 return nameSet; 472 } 473 } 474 475 private WorkspaceNode getOrCreateWorkspaceNode(Fqn fqn, TransactionWorkspace workspace, boolean undeleteIfNecessary) 476 { 477 WorkspaceNode workspaceNode = workspace.getNode(fqn); 478 if (workspaceNode == null) 480 { 481 NodeSPI node = cache.peek(fqn); 482 if (node == null) 483 { 484 return null; } 486 workspaceNode = nodeFactory.createWorkspaceNode(node, workspace); 487 workspace.addNode(workspaceNode); 488 } 489 if (workspaceNode.isDeleted()) 491 { 492 if (log.isDebugEnabled()) log.debug("Node " + fqn + " has been deleted in the workspace."); 493 if (undeleteIfNecessary) 494 { 495 workspaceNode.markAsDeleted(false); 496 } 497 else 498 { 499 workspaceNode = null; 500 } 501 } 502 return workspaceNode; 503 } 504 } 505 | Popular Tags |