1 19 20 package org.apache.cayenne.map; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Collections ; 25 import java.util.Comparator ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 31 import org.apache.cayenne.CayenneRuntimeException; 32 import org.apache.cayenne.DataRow; 33 import org.apache.cayenne.ObjectContext; 34 import org.apache.cayenne.ObjectId; 35 import org.apache.cayenne.Persistent; 36 import org.apache.cayenne.QueryResponse; 37 import org.apache.cayenne.query.ObjectIdQuery; 38 import org.apache.cayenne.reflect.ClassDescriptor; 39 import org.apache.commons.collections.comparators.ReverseComparator; 40 import org.objectstyle.ashwood.dbutil.DbUtils; 41 import org.objectstyle.ashwood.dbutil.ForeignKey; 42 import org.objectstyle.ashwood.dbutil.Table; 43 import org.objectstyle.ashwood.graph.CollectionFactory; 44 import org.objectstyle.ashwood.graph.Digraph; 45 import org.objectstyle.ashwood.graph.IndegreeTopologicalSort; 46 import org.objectstyle.ashwood.graph.MapDigraph; 47 import org.objectstyle.ashwood.graph.StrongConnection; 48 49 58 public class AshwoodEntitySorter implements EntitySorter { 59 60 protected Collection dataMaps; 61 protected Map dbEntityToTableMap; 62 protected Digraph referentialDigraph; 63 protected Digraph contractedReferentialDigraph; 64 protected Map components; 65 protected Map reflexiveDbEntities; 66 67 protected TableComparator tableComparator; 68 protected DbEntityComparator dbEntityComparator; 69 protected ObjEntityComparator objEntityComparator; 70 71 protected boolean dirty; 73 74 public AshwoodEntitySorter(Collection dataMaps) { 75 tableComparator = new TableComparator(); 76 dbEntityComparator = new DbEntityComparator(); 77 objEntityComparator = new ObjEntityComparator(); 78 79 setDataMaps(dataMaps); 80 } 81 82 85 protected synchronized void _indexSorter() { 86 if (!dirty) { 87 return; 88 } 89 90 Collection tables = new ArrayList (64); 91 dbEntityToTableMap = new HashMap (64); 92 reflexiveDbEntities = new HashMap (32); 93 for (Iterator i = dataMaps.iterator(); i.hasNext();) { 94 DataMap map = (DataMap) i.next(); 95 Iterator entitiesToConvert = map.getDbEntities().iterator(); 96 while (entitiesToConvert.hasNext()) { 97 DbEntity entity = (DbEntity) entitiesToConvert.next(); 98 Table table = new Table(entity.getCatalog(), entity.getSchema(), entity 99 .getName()); 100 fillInMetadata(table, entity); 101 dbEntityToTableMap.put(entity, table); 102 tables.add(table); 103 } 104 } 105 referentialDigraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 106 DbUtils.buildReferentialDigraph(referentialDigraph, tables); 107 StrongConnection contractor = new StrongConnection( 108 referentialDigraph, 109 CollectionFactory.ARRAYLIST_FACTORY); 110 contractedReferentialDigraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 111 contractor.contract( 112 contractedReferentialDigraph, 113 CollectionFactory.ARRAYLIST_FACTORY); 114 IndegreeTopologicalSort sorter = new IndegreeTopologicalSort( 115 contractedReferentialDigraph); 116 components = new HashMap (contractedReferentialDigraph.order()); 117 int componentIndex = 0; 118 while (sorter.hasNext()) { 119 Collection component = (Collection ) sorter.next(); 120 ComponentRecord rec = new ComponentRecord(componentIndex++, component); 121 for (Iterator i = component.iterator(); i.hasNext();) { 122 components.put(i.next(), rec); 123 } 124 } 125 126 this.dirty = false; 128 } 129 130 133 public synchronized void setDataMaps(Collection dataMaps) { 134 this.dirty = true; 135 this.dataMaps = dataMaps != null ? dataMaps : Collections.EMPTY_LIST; 136 } 137 138 public void sortDbEntities(List dbEntities, boolean deleteOrder) { 139 _indexSorter(); 140 Collections.sort(dbEntities, getDbEntityComparator(deleteOrder)); 141 } 142 143 public void sortObjEntities(List objEntities, boolean deleteOrder) { 144 _indexSorter(); 145 Collections.sort(objEntities, getObjEntityComparator(deleteOrder)); 146 } 147 148 public void sortObjectsForEntity( 149 ObjEntity objEntity, 150 List objects, 151 boolean deleteOrder) { 152 153 _indexSorter(); 155 156 DbEntity dbEntity = objEntity.getDbEntity(); 157 158 if (!isReflexive(dbEntity)) { 160 return; 161 } 162 163 int size = objects.size(); 164 if (size == 0) { 165 return; 166 } 167 168 EntityResolver resolver = ((Persistent) objects.get(0)) 169 .getObjectContext() 170 .getEntityResolver(); 171 ClassDescriptor descriptor = resolver.getClassDescriptor(objEntity.getName()); 172 173 List reflexiveRels = (List ) reflexiveDbEntities.get(dbEntity); 174 String [] reflexiveRelNames = new String [reflexiveRels.size()]; 175 for (int i = 0; i < reflexiveRelNames.length; i++) { 176 DbRelationship dbRel = (DbRelationship) reflexiveRels.get(i); 177 ObjRelationship objRel = (dbRel != null ? objEntity 178 .getRelationshipForDbRelationship(dbRel) : null); 179 reflexiveRelNames[i] = (objRel != null ? objRel.getName() : null); 180 } 181 182 List sorted = new ArrayList (size); 183 184 Digraph objectDependencyGraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 185 Object [] masters = new Object [reflexiveRelNames.length]; 186 for (int i = 0; i < size; i++) { 187 Persistent current = (Persistent) objects.get(i); 188 objectDependencyGraph.addVertex(current); 189 int actualMasterCount = 0; 190 for (int k = 0; k < reflexiveRelNames.length; k++) { 191 String reflexiveRelName = reflexiveRelNames[k]; 192 193 if (reflexiveRelName == null) { 194 continue; 195 } 196 197 masters[k] = (reflexiveRelName != null) ? descriptor.getProperty( 198 reflexiveRelName).readProperty(current) : null; 199 200 if (masters[k] == null) { 201 masters[k] = findReflexiveMaster(current, (ObjRelationship) objEntity 202 .getRelationship(reflexiveRelName), current 203 .getObjectId() 204 .getEntityName()); 205 } 206 207 if (masters[k] != null) { 208 actualMasterCount++; 209 } 210 } 211 212 int mastersFound = 0; 213 for (int j = 0; j < size && mastersFound < actualMasterCount; j++) { 214 215 if (i == j) { 216 continue; 217 } 218 219 Object masterCandidate = objects.get(j); 220 for (int k = 0; k < masters.length; k++) { 221 if (masterCandidate.equals(masters[k])) { 222 objectDependencyGraph.putArc( 223 masterCandidate, 224 current, 225 Boolean.TRUE); 226 mastersFound++; 227 } 228 } 229 } 230 } 231 232 IndegreeTopologicalSort sorter = new IndegreeTopologicalSort( 233 objectDependencyGraph); 234 235 while (sorter.hasNext()) { 236 Object o = sorter.next(); 237 if (o == null) 238 throw new CayenneRuntimeException("Sorting objects for " 239 + objEntity.getClassName() 240 + " failed. Cycles found."); 241 sorted.add(o); 242 } 243 244 objects.clear(); 248 objects.addAll(sorted); 249 250 if (deleteOrder) { 251 Collections.reverse(objects); 252 } 253 } 254 255 protected void fillInMetadata(Table table, DbEntity entity) { 256 short keySequence = 1; 258 Iterator i = entity.getRelationshipMap().values().iterator(); 259 260 while (i.hasNext()) { 261 DbRelationship candidate = (DbRelationship) i.next(); 262 if ((!candidate.isToMany() && !candidate.isToDependentPK()) 263 || candidate.isToMasterPK()) { 264 DbEntity target = (DbEntity) candidate.getTargetEntity(); 265 boolean newReflexive = entity.equals(target); 266 Iterator j = candidate.getJoins().iterator(); 267 while (j.hasNext()) { 268 DbJoin join = (DbJoin) j.next(); 269 DbAttribute targetAttribute = join.getTarget(); 270 if (targetAttribute.isPrimaryKey()) { 271 ForeignKey fk = new ForeignKey(); 272 fk.setPkTableCatalog(target.getCatalog()); 273 fk.setPkTableSchema(target.getSchema()); 274 fk.setPkTableName(target.getName()); 275 fk.setPkColumnName(targetAttribute.getName()); 276 fk.setColumnName(join.getSourceName()); 277 fk.setKeySequence(keySequence++); 278 table.addForeignKey(fk); 279 280 if (newReflexive) { 281 List reflexiveRels = (List ) reflexiveDbEntities.get(entity); 282 if (reflexiveRels == null) { 283 reflexiveRels = new ArrayList (1); 284 reflexiveDbEntities.put(entity, reflexiveRels); 285 } 286 reflexiveRels.add(candidate); 287 newReflexive = false; 288 } 289 } 290 } 291 } 292 } 293 } 294 295 protected Object findReflexiveMaster( 296 Persistent object, 297 ObjRelationship toOneRel, 298 String targetEntityName) { 299 300 DbRelationship finalRel = (DbRelationship) toOneRel.getDbRelationships().get(0); 301 ObjectContext context = object.getObjectContext(); 302 303 ObjectIdQuery query = new ObjectIdQuery( 306 object.getObjectId(), 307 true, 308 ObjectIdQuery.CACHE); 309 QueryResponse response = context.getChannel().onQuery(null, query); 310 List result = response.firstList(); 311 if(result == null || result.size() == 0) { 312 return null; 313 } 314 315 DataRow snapshot = (DataRow) result.get(0); 316 317 ObjectId id = snapshot.createTargetObjectId(targetEntityName, finalRel); 318 return (id != null) ? context.localObject(id, null) : null; 319 } 320 321 protected Comparator getDbEntityComparator(boolean dependantFirst) { 322 Comparator c = dbEntityComparator; 323 if (dependantFirst) { 324 c = new ReverseComparator(c); 325 } 326 return c; 327 } 328 329 protected Comparator getObjEntityComparator(boolean dependantFirst) { 330 Comparator c = objEntityComparator; 331 if (dependantFirst) { 332 c = new ReverseComparator(c); 333 } 334 return c; 335 } 336 337 protected Table getTable(DbEntity dbEntity) { 338 return (dbEntity != null) ? (Table) dbEntityToTableMap.get(dbEntity) : null; 339 } 340 341 protected Table getTable(ObjEntity objEntity) { 342 return getTable(objEntity.getDbEntity()); 343 } 344 345 protected boolean isReflexive(DbEntity metadata) { 346 return reflexiveDbEntities.containsKey(metadata); 347 } 348 349 private final class DbEntityComparator implements Comparator { 350 351 public int compare(Object o1, Object o2) { 352 if (o1 == o2) 353 return 0; 354 Table t1 = getTable((DbEntity) o1); 355 Table t2 = getTable((DbEntity) o2); 356 return tableComparator.compare(t1, t2); 357 } 358 } 359 360 private final class ObjEntityComparator implements Comparator { 361 362 public int compare(Object o1, Object o2) { 363 if (o1 == o2) 364 return 0; 365 Table t1 = getTable((ObjEntity) o1); 366 Table t2 = getTable((ObjEntity) o2); 367 return tableComparator.compare(t1, t2); 368 } 369 } 370 371 private final class TableComparator implements Comparator { 372 373 public int compare(Object o1, Object o2) { 374 int result = 0; 375 Table t1 = (Table) o1; 376 Table t2 = (Table) o2; 377 if (t1 == t2) 378 return 0; 379 if (t1 == null) 380 result = -1; 381 else if (t2 == null) 382 result = 1; 383 else { 384 ComponentRecord rec1 = (ComponentRecord) components.get(t1); 385 ComponentRecord rec2 = (ComponentRecord) components.get(t2); 386 int index1 = rec1.index; 387 int index2 = rec2.index; 388 result = (index1 > index2 ? 1 : (index1 < index2 ? -1 : 0)); 389 if (result != 0 && rec1.component == rec2.component) 390 result = 0; 391 } 392 return result; 393 } 394 } 395 396 private final static class ComponentRecord { 397 398 ComponentRecord(int index, Collection component) { 399 this.index = index; 400 this.component = component; 401 } 402 403 int index; 404 Collection component; 405 } 406 407 } 408 | Popular Tags |