1 56 package org.objectstyle.cayenne.access.util; 57 58 import java.util.ArrayList ; 59 import java.util.HashMap ; 60 import java.util.Iterator ; 61 import java.util.List ; 62 import java.util.Map ; 63 64 import org.apache.commons.collections.Factory; 65 import org.apache.commons.collections.MapUtils; 66 import org.apache.commons.collections.map.LinkedMap; 67 import org.apache.log4j.Logger; 68 import org.objectstyle.cayenne.DataObject; 69 import org.objectstyle.cayenne.ObjectFactory; 70 import org.objectstyle.cayenne.ObjectId; 71 import org.objectstyle.cayenne.PersistenceState; 72 import org.objectstyle.cayenne.access.DataContext; 73 import org.objectstyle.cayenne.access.ObjectStore; 74 import org.objectstyle.cayenne.access.ToManyList; 75 import org.objectstyle.cayenne.conf.Configuration; 76 import org.objectstyle.cayenne.map.DbRelationship; 77 import org.objectstyle.cayenne.map.ObjEntity; 78 import org.objectstyle.cayenne.map.ObjRelationship; 79 import org.objectstyle.cayenne.query.PrefetchSelectQuery; 80 import org.objectstyle.cayenne.query.Query; 81 82 89 class PrefetchResolver { 90 91 private static final Logger logObj = Logger.getLogger(PrefetchResolver.class); 92 93 List dataRows; 94 ObjEntity entity; 95 ObjRelationship incoming; 96 Map children; 97 98 ObjRelationship getIncoming() { 99 return incoming; 100 } 101 102 void setIncoming(ObjRelationship incoming) { 103 this.incoming = incoming; 104 } 105 106 109 void buildTree(ObjEntity entity, Query rootQuery, Map resultsByQuery) { 110 this.entity = entity; 111 112 Iterator it = resultsByQuery.entrySet().iterator(); 114 115 while (it.hasNext()) { 116 Map.Entry entry = (Map.Entry ) it.next(); 117 118 Query query = (Query) entry.getKey(); 119 List dataRows = (List ) entry.getValue(); 120 121 if (dataRows == null) { 122 logObj.warn("Can't find prefetch results for query: " + query); 123 continue; 124 125 } 129 130 if (rootQuery == query) { 131 this.dataRows = dataRows; 132 continue; 133 } 134 135 if (query instanceof PrefetchSelectQuery) { 137 PrefetchSelectQuery prefetchQuery = (PrefetchSelectQuery) query; 138 139 if (prefetchQuery.getParentQuery() == rootQuery) { 140 addChildWithPath(prefetchQuery.getPrefetchPath(), dataRows); 141 } 142 } 143 } 144 } 145 146 149 PrefetchResolver addChildWithPath(String prefetchPath, List dataRows) { 150 Iterator it = entity.resolvePathComponents(prefetchPath); 151 152 if (!it.hasNext()) { 153 return null; 154 } 155 156 PrefetchResolver lastChild = this; 157 158 while (it.hasNext()) { 159 ObjRelationship r = (ObjRelationship) it.next(); 160 lastChild = lastChild.addChild(r); 161 } 162 163 lastChild.dataRows = dataRows; 164 return lastChild; 165 } 166 167 170 PrefetchResolver addChild(ObjRelationship outgoing) { 171 PrefetchResolver child = null; 172 173 if (children == null) { 174 children = new LinkedMap(); 175 } 176 else { 177 child = (PrefetchResolver) children.get(outgoing.getName()); 178 } 179 180 if (child == null) { 181 child = new PrefetchResolver(); 182 child.setIncoming(outgoing); 183 children.put(outgoing.getName(), child); 184 } 185 186 return child; 187 } 188 189 192 List resolveObjectTree(ObjectFactory factory) { 193 194 List objects = resolveObjectTree(factory, null, false); 196 return (objects != null) ? objects : new ArrayList (1); 197 } 198 199 204 List resolveObjectTree(ObjectFactory factory, List parentObjects, boolean skipSelf) { 205 206 List objects = null; 207 208 if (!skipSelf && dataRows != null) { 210 ObjEntity entity = (incoming != null) ? (ObjEntity) incoming 211 .getTargetEntity() : this.entity; 212 213 objects = factory.objectsFromDataRows(entity, dataRows); 215 216 if (incoming != null && incoming.isToMany()) { 219 220 Map partitioned = partitionBySource(objects); 221 222 225 if (parentObjects != null && parentObjects.size() > 0) { 226 connectToNodeParents(parentObjects, partitioned); 227 } 228 else { 229 connectToFaultedParents(partitioned); 230 } 231 } 232 } 233 234 if (children != null) { 236 Iterator it = children.entrySet().iterator(); 237 while (it.hasNext()) { 238 Map.Entry entry = (Map.Entry ) it.next(); 239 PrefetchResolver node = (PrefetchResolver) entry.getValue(); 240 node.resolveObjectTree(factory, objects, false); 241 } 242 } 243 244 return objects; 245 } 246 247 void connectToNodeParents(List parentObjects, Map partitioned) { 248 249 252 Iterator it = parentObjects.iterator(); 253 while (it.hasNext()) { 254 DataObject root = (DataObject) it.next(); 255 List related = (List ) partitioned.get(root); 256 257 if (related == null) { 258 related = new ArrayList (1); 259 } 260 261 ToManyList toManyList = (ToManyList) root.readProperty(incoming.getName()); 262 toManyList.setObjectList(related); 263 } 264 } 265 266 void connectToFaultedParents(Map partitioned) { 267 Iterator it = partitioned.entrySet().iterator(); 268 while (it.hasNext()) { 269 Map.Entry entry = (Map.Entry ) it.next(); 270 271 DataObject root = (DataObject) entry.getKey(); 272 List related = (List ) entry.getValue(); 273 274 ToManyList toManyList = (ToManyList) root.readProperty(incoming.getName()); 275 276 toManyList.setObjectList(related); 279 } 280 } 281 282 286 Map partitionBySource(List objects) { 287 Class sourceObjectClass = ((ObjEntity) incoming.getSourceEntity()) 288 .getJavaClass(Configuration.getResourceLoader()); 289 ObjRelationship reverseRelationship = incoming.getReverseRelationship(); 290 291 DbRelationship dbRelationship = (DbRelationship) incoming 293 .getDbRelationships() 294 .get(0); 295 296 Factory listFactory = new Factory() { 297 298 public Object create() { 299 return new ArrayList (); 300 } 301 }; 302 303 Map toManyLists = MapUtils.lazyMap(new HashMap (), listFactory); 304 Iterator destIterator = objects.iterator(); 305 while (destIterator.hasNext()) { 306 DataObject destinationObject = (DataObject) destIterator.next(); 307 DataObject sourceObject = null; 308 if (reverseRelationship != null) { 309 sourceObject = (DataObject) destinationObject 310 .readProperty(reverseRelationship.getName()); 311 } 312 else { 313 DataContext context = destinationObject.getDataContext(); 315 ObjectStore objectStore = context.getObjectStore(); 316 317 Map sourcePk = dbRelationship.srcPkSnapshotWithTargetSnapshot(objectStore 318 .getSnapshot(destinationObject.getObjectId(), context)); 319 320 sourceObject = objectStore.getObject(new ObjectId( 324 sourceObjectClass, 325 sourcePk)); 326 } 327 328 if (sourceObject != null 330 && sourceObject.getPersistenceState() != PersistenceState.HOLLOW) { 331 List relatedObjects = (List ) toManyLists.get(sourceObject); 332 relatedObjects.add(destinationObject); 333 } 334 } 335 336 return toManyLists; 337 } 338 } | Popular Tags |