1 19 20 package org.apache.cayenne.access; 21 22 import java.util.ArrayList ; 23 import java.util.Iterator ; 24 import java.util.LinkedList ; 25 import java.util.List ; 26 import java.util.Map ; 27 28 import org.apache.cayenne.CayenneRuntimeException; 29 import org.apache.cayenne.DataRow; 30 import org.apache.cayenne.ObjectId; 31 import org.apache.cayenne.PersistenceState; 32 import org.apache.cayenne.Persistent; 33 import org.apache.cayenne.map.ObjEntity; 34 import org.apache.cayenne.query.PrefetchProcessor; 35 import org.apache.cayenne.query.PrefetchTreeNode; 36 import org.apache.cayenne.query.QueryMetadata; 37 import org.apache.cayenne.reflect.ArcProperty; 38 import org.apache.cayenne.reflect.ClassDescriptor; 39 40 48 class ObjectTreeResolver { 49 50 DataContext context; 51 QueryMetadata queryMetadata; 52 DataRowStore cache; 53 54 ObjectTreeResolver(DataContext context, QueryMetadata queryMetadata) { 55 this.queryMetadata = queryMetadata; 56 this.context = context; 57 this.cache = context.getObjectStore().getDataRowCache(); 58 } 59 60 63 List synchronizedObjectsFromDataRows( 64 PrefetchTreeNode tree, 65 List mainResultRows, 66 Map extraResultsByPath) { 67 68 synchronized (context.getObjectStore()) { 69 synchronized (cache) { 70 return resolveObjectTree(tree, mainResultRows, extraResultsByPath); 71 } 72 } 73 } 74 75 List resolveObjectTree( 76 PrefetchTreeNode tree, 77 List mainResultRows, 78 Map extraResultsByPath) { 79 80 PrefetchProcessorNode decoratedTree = new TreeBuilder( 83 mainResultRows, 84 extraResultsByPath).buildTree(tree); 85 86 decoratedTree.traverse(new DisjointProcessor()); 89 90 decoratedTree.traverse(new PostProcessor()); 92 93 return decoratedTree.getObjects() != null 94 ? decoratedTree.getObjects() 95 : new ArrayList (1); 96 } 97 98 final class TreeBuilder implements PrefetchProcessor { 101 102 PrefetchProcessorNode root; 103 LinkedList nodeStack; 104 105 List mainResultRows; 106 Map extraResultsByPath; 107 108 TreeBuilder(List mainResultRows, Map extraResultsByPath) { 109 this.mainResultRows = mainResultRows; 110 this.extraResultsByPath = extraResultsByPath; 111 } 112 113 PrefetchProcessorNode buildTree(PrefetchTreeNode tree) { 114 this.nodeStack = new LinkedList (); 116 this.root = null; 117 118 tree.traverse(this); 119 120 if (root == null) { 121 throw new CayenneRuntimeException( 122 "Failed to create prefetch processing tree."); 123 } 124 125 return root; 126 } 127 128 public boolean startPhantomPrefetch(PrefetchTreeNode node) { 129 130 if (getParent() == null) { 132 return startDisjointPrefetch(node); 133 } 134 else { 135 PrefetchProcessorNode decorated = new PrefetchProcessorNode( 136 getParent(), 137 node.getName()); 138 139 decorated.setPhantom(true); 140 return addNode(decorated); 141 } 142 } 143 144 public boolean startDisjointPrefetch(PrefetchTreeNode node) { 145 146 149 PrefetchProcessorNode decorated = !node.adjacentJointNodes().isEmpty() 152 ? new PrefetchProcessorJointNode(getParent(), node.getName()) 153 : new PrefetchProcessorNode(getParent(), node.getName()); 154 decorated.setPhantom(false); 155 156 decorated.setSemantics(PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS); 159 return addNode(decorated); 160 } 161 162 public boolean startJointPrefetch(PrefetchTreeNode node) { 163 PrefetchProcessorJointNode decorated = new PrefetchProcessorJointNode( 164 getParent(), 165 node.getName()); 166 decorated.setPhantom(false); 167 decorated.setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS); 168 boolean result = addNode(decorated); 169 170 PrefetchProcessorNode groupNode = decorated; 172 while (groupNode.getParent() != null && !groupNode.isDisjointPrefetch()) { 173 groupNode = (PrefetchProcessorNode) groupNode.getParent(); 174 groupNode.setJointChildren(true); 175 } 176 177 return result; 178 } 179 180 public boolean startUnknownPrefetch(PrefetchTreeNode node) { 181 return startDisjointPrefetch(node); 183 } 184 185 public void finishPrefetch(PrefetchTreeNode node) { 186 nodeStack.removeLast(); 188 } 189 190 boolean addNode(PrefetchProcessorNode node) { 191 192 List rows; 193 ArcProperty arc; 194 ClassDescriptor descriptor; 195 196 PrefetchProcessorNode currentNode = getParent(); 197 198 if (currentNode != null) { 199 rows = (List ) extraResultsByPath.get(node.getPath()); 200 arc = (ArcProperty) currentNode 201 .getResolver() 202 .getDescriptor() 203 .getProperty(node.getName()); 204 205 if (arc == null) { 206 throw new CayenneRuntimeException("No relationship with name '" 207 + node.getName() 208 + "' found in entity " 209 + currentNode.getResolver().getEntity().getName()); 210 } 211 212 descriptor = arc.getTargetDescriptor(); 213 } 214 else { 215 arc = null; 216 descriptor = queryMetadata.getClassDescriptor(); 217 rows = mainResultRows; 218 } 219 220 node.setDataRows(rows); 221 node.setResolver(new ObjectResolver(context, descriptor, queryMetadata 222 .isRefreshingObjects(), queryMetadata.isResolvingInherited())); 223 node.setIncoming(arc); 224 225 if (currentNode != null) { 226 currentNode.addChild(node); 227 } 228 229 node.afterInit(); 230 231 if (nodeStack.isEmpty()) { 233 root = node; 234 } 235 nodeStack.addLast(node); 236 237 return true; 238 } 239 240 PrefetchProcessorNode getParent() { 241 return (nodeStack.isEmpty()) ? null : (PrefetchProcessorNode) nodeStack 242 .getLast(); 243 } 244 } 245 246 final class DisjointProcessor implements PrefetchProcessor { 247 248 public boolean startDisjointPrefetch(PrefetchTreeNode node) { 249 250 PrefetchProcessorNode processorNode = (PrefetchProcessorNode) node; 251 252 if (processorNode.getDataRows() == null) { 254 return false; 255 } 256 257 if (processorNode.getDataRows().isEmpty()) { 260 return true; 261 } 262 263 List objects; 264 265 if (processorNode instanceof PrefetchProcessorJointNode) { 268 JointProcessor subprocessor = new JointProcessor( 269 (PrefetchProcessorJointNode) processorNode); 270 Iterator it = processorNode.getDataRows().iterator(); 271 while (it.hasNext()) { 272 subprocessor.setCurrentFlatRow((DataRow) it.next()); 273 processorNode.traverse(subprocessor); 274 } 275 276 objects = processorNode.getObjects(); 277 278 cache.snapshotsUpdatedForObjects( 279 objects, 280 ((PrefetchProcessorJointNode) processorNode).getResolvedRows(), 281 queryMetadata.isRefreshingObjects()); 282 } 283 else if (processorNode.getIncoming() != null 285 && processorNode.getIncoming().getRelationship().isFlattened()) { 286 287 objects = processorNode.getResolver().relatedObjectsFromDataRows( 288 processorNode.getDataRows(), 289 processorNode); 290 processorNode.setObjects(objects); 291 } 292 else { 293 objects = processorNode.getResolver().objectsFromDataRows( 294 processorNode.getDataRows()); 295 processorNode.setObjects(objects); 296 } 297 298 if (objects.isEmpty()) { 301 return true; 302 } 303 304 if (processorNode.isPartitionedByParent() 307 && !processorNode.getIncoming().getRelationship().isFlattened()) { 308 309 ObjEntity sourceObjEntity = null; 310 String relatedIdPrefix = null; 311 312 ArcProperty reverseArc = processorNode 314 .getIncoming() 315 .getComplimentaryReverseArc(); 316 317 if (reverseArc == null) { 319 relatedIdPrefix = processorNode 320 .getIncoming() 321 .getRelationship() 322 .getReverseDbRelationshipPath() 323 + "."; 324 325 sourceObjEntity = (ObjEntity) processorNode 326 .getIncoming() 327 .getRelationship() 328 .getSourceEntity(); 329 } 330 331 Iterator it = objects.iterator(); 332 while (it.hasNext()) { 333 Persistent destinationObject = (Persistent) it.next(); 334 Persistent sourceObject = null; 335 336 if (reverseArc != null) { 337 sourceObject = (Persistent) reverseArc 338 .readProperty(destinationObject); 339 } 340 else { 341 ObjectStore objectStore = context.getObjectStore(); 342 343 346 DataRow snapshot = objectStore.getSnapshot(destinationObject 347 .getObjectId()); 348 349 ObjectId id = processorNode.getResolver().createObjectId( 350 snapshot, 351 sourceObjEntity, 352 relatedIdPrefix); 353 354 sourceObject = (Persistent) objectStore.getNode(id); 355 } 356 357 if (sourceObject != null 359 && sourceObject.getPersistenceState() != PersistenceState.HOLLOW) { 360 processorNode.linkToParent(destinationObject, sourceObject); 361 } 362 } 363 } 364 365 return true; 366 } 367 368 public boolean startJointPrefetch(PrefetchTreeNode node) { 369 return true; 372 } 373 374 public boolean startPhantomPrefetch(PrefetchTreeNode node) { 375 return true; 376 } 377 378 public boolean startUnknownPrefetch(PrefetchTreeNode node) { 379 throw new CayenneRuntimeException("Unknown prefetch node: " + node); 380 } 381 382 public void finishPrefetch(PrefetchTreeNode node) { 383 } 385 } 386 387 final class JointProcessor implements PrefetchProcessor { 390 391 DataRow currentFlatRow; 392 PrefetchProcessorNode rootNode; 393 394 JointProcessor(PrefetchProcessorJointNode rootNode) { 395 this.rootNode = rootNode; 396 } 397 398 void setCurrentFlatRow(DataRow currentFlatRow) { 399 this.currentFlatRow = currentFlatRow; 400 } 401 402 public boolean startDisjointPrefetch(PrefetchTreeNode node) { 403 return node == rootNode ? startJointPrefetch(node) : false; 405 } 406 407 public boolean startJointPrefetch(PrefetchTreeNode node) { 408 PrefetchProcessorJointNode processorNode = (PrefetchProcessorJointNode) node; 409 410 Persistent object = null; 411 412 Map id = processorNode.idFromFlatRow(currentFlatRow); 414 object = processorNode.getResolved(id); 415 416 if (object == null) { 417 418 DataRow row = processorNode.rowFromFlatRow(currentFlatRow); 419 object = processorNode.getResolver().objectFromDataRow(row); 420 421 processorNode.putResolved(id, object); 422 processorNode.addObject(object, row); 423 } 424 425 if (processorNode.isPartitionedByParent()) { 428 429 PrefetchProcessorNode parent = (PrefetchProcessorNode) processorNode 430 .getParent(); 431 processorNode.linkToParent(object, parent.getLastResolved()); 432 } 433 434 processorNode.setLastResolved(object); 435 return processorNode.isJointChildren(); 436 } 437 438 public boolean startPhantomPrefetch(PrefetchTreeNode node) { 439 return ((PrefetchProcessorNode) node).isJointChildren(); 440 } 441 442 public boolean startUnknownPrefetch(PrefetchTreeNode node) { 443 throw new CayenneRuntimeException("Unknown prefetch node: " + node); 444 } 445 446 public void finishPrefetch(PrefetchTreeNode node) { 447 } 449 } 450 451 final class PostProcessor implements PrefetchProcessor { 454 455 public void finishPrefetch(PrefetchTreeNode node) { 456 } 457 458 public boolean startDisjointPrefetch(PrefetchTreeNode node) { 459 ((PrefetchProcessorNode) node).connectToParents(); 460 return true; 461 } 462 463 public boolean startJointPrefetch(PrefetchTreeNode node) { 464 PrefetchProcessorJointNode processorNode = (PrefetchProcessorJointNode) node; 465 466 if (!processorNode.getObjects().isEmpty()) { 467 cache.snapshotsUpdatedForObjects( 468 processorNode.getObjects(), 469 processorNode.getResolvedRows(), 470 queryMetadata.isRefreshingObjects()); 471 processorNode.connectToParents(); 472 } 473 474 return true; 475 } 476 477 public boolean startPhantomPrefetch(PrefetchTreeNode node) { 478 return true; 479 } 480 481 public boolean startUnknownPrefetch(PrefetchTreeNode node) { 482 throw new CayenneRuntimeException("Unknown prefetch node: " + node); 483 } 484 } 485 } 486 | Popular Tags |