1 56 57 package org.objectstyle.cayenne.map; 58 59 import java.util.ArrayList ; 60 import java.util.Collection ; 61 import java.util.Collections ; 62 import java.util.Comparator ; 63 import java.util.HashMap ; 64 import java.util.Iterator ; 65 import java.util.List ; 66 import java.util.Map ; 67 68 import org.apache.commons.collections.comparators.ReverseComparator; 69 import org.objectstyle.ashwood.dbutil.DbUtils; 70 import org.objectstyle.ashwood.dbutil.ForeignKey; 71 import org.objectstyle.ashwood.dbutil.Table; 72 import org.objectstyle.ashwood.graph.CollectionFactory; 73 import org.objectstyle.ashwood.graph.Digraph; 74 import org.objectstyle.ashwood.graph.IndegreeTopologicalSort; 75 import org.objectstyle.ashwood.graph.MapDigraph; 76 import org.objectstyle.ashwood.graph.StrongConnection; 77 import org.objectstyle.cayenne.CayenneRuntimeException; 78 import org.objectstyle.cayenne.DataObject; 79 import org.objectstyle.cayenne.DataRow; 80 import org.objectstyle.cayenne.ObjectId; 81 import org.objectstyle.cayenne.PersistenceState; 82 import org.objectstyle.cayenne.access.DataContext; 83 import org.objectstyle.cayenne.access.QueryEngine; 84 85 94 public class AshwoodEntitySorter implements EntitySorter { 95 protected Collection dataMaps; 96 protected Map dbEntityToTableMap; 97 protected Digraph referentialDigraph; 98 protected Digraph contractedReferentialDigraph; 99 protected Map components; 100 protected Map reflexiveDbEntities; 101 102 protected TableComparator tableComparator; 103 protected DbEntityComparator dbEntityComparator; 104 protected ObjEntityComparator objEntityComparator; 105 106 protected boolean dirty; 108 109 public AshwoodEntitySorter(Collection dataMaps) { 110 setDataMaps(dataMaps); 111 } 112 113 116 protected synchronized void _indexSorter() { 117 if (!dirty) { 118 return; 119 } 120 121 Collection tables = new ArrayList (64); 122 dbEntityToTableMap = new HashMap (64); 123 reflexiveDbEntities = new HashMap (32); 124 for (Iterator i = dataMaps.iterator(); i.hasNext();) { 125 DataMap map = (DataMap) i.next(); 126 Iterator entitiesToConvert = map.getDbEntities().iterator(); 127 while (entitiesToConvert.hasNext()) { 128 DbEntity entity = (DbEntity) entitiesToConvert.next(); 129 Table table = 130 new Table(entity.getCatalog(), entity.getSchema(), entity.getName()); 131 fillInMetadata(table, entity); 132 dbEntityToTableMap.put(entity, table); 133 tables.add(table); 134 } 135 } 136 referentialDigraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 137 DbUtils.buildReferentialDigraph(referentialDigraph, tables); 138 StrongConnection contractor = 139 new StrongConnection(referentialDigraph, CollectionFactory.ARRAYLIST_FACTORY); 140 contractedReferentialDigraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 141 contractor.contract( 142 contractedReferentialDigraph, 143 CollectionFactory.ARRAYLIST_FACTORY); 144 IndegreeTopologicalSort sorter = 145 new IndegreeTopologicalSort(contractedReferentialDigraph); 146 components = new HashMap (contractedReferentialDigraph.order()); 147 int componentIndex = 0; 148 while (sorter.hasNext()) { 149 Collection component = (Collection ) sorter.next(); 150 ComponentRecord rec = new ComponentRecord(componentIndex++, component); 151 for (Iterator i = component.iterator(); i.hasNext();) { 152 components.put(i.next(), rec); 153 } 154 } 155 156 tableComparator = new TableComparator(); 157 dbEntityComparator = new DbEntityComparator(); 158 objEntityComparator = new ObjEntityComparator(); 159 160 this.dirty = false; 162 } 163 164 167 public synchronized void setDataMaps(Collection dataMaps) { 168 this.dirty = true; 169 this.dataMaps = dataMaps != null ? dataMaps : Collections.EMPTY_LIST; 170 } 171 172 176 public void indexSorter(QueryEngine queryEngine) { 177 setDataMaps(queryEngine.getDataMaps()); 178 } 179 180 public void sortDbEntities(List dbEntities, boolean deleteOrder) { 181 _indexSorter(); 182 Collections.sort(dbEntities, getDbEntityComparator(deleteOrder)); 183 } 184 185 public void sortObjEntities(List objEntities, boolean deleteOrder) { 186 _indexSorter(); 187 Collections.sort(objEntities, getObjEntityComparator(deleteOrder)); 188 } 189 190 public void sortObjectsForEntity( 191 ObjEntity objEntity, 192 List objects, 193 boolean deleteOrder) { 194 195 _indexSorter(); 197 198 DbEntity dbEntity = objEntity.getDbEntity(); 199 200 if (!isReflexive(dbEntity)) { 202 return; 203 } 204 205 int size = objects.size(); 206 List reflexiveRels = (List ) reflexiveDbEntities.get(dbEntity); 207 String [] reflexiveRelNames = new String [reflexiveRels.size()]; 208 for (int i = 0; i < reflexiveRelNames.length; i++) { 209 DbRelationship dbRel = (DbRelationship) reflexiveRels.get(i); 210 ObjRelationship objRel = 211 (dbRel != null 212 ? objEntity.getRelationshipForDbRelationship(dbRel) 213 : null); 214 reflexiveRelNames[i] = (objRel != null ? objRel.getName() : null); 215 } 216 217 List sorted = new ArrayList (size); 218 219 Digraph objectDependencyGraph = new MapDigraph(MapDigraph.HASHMAP_FACTORY); 220 Object [] masters = new Object [reflexiveRelNames.length]; 221 for (int i = 0; i < size; i++) { 222 DataObject current = (DataObject) objects.get(i); 223 objectDependencyGraph.addVertex(current); 224 int actualMasterCount = 0; 225 for (int k = 0; k < reflexiveRelNames.length; k++) { 226 String reflexiveRelName = reflexiveRelNames[k]; 227 228 if (reflexiveRelName == null) { 229 continue; 230 } 231 232 masters[k] = 233 (reflexiveRelName != null) 234 ? current.readProperty(reflexiveRelName) 235 : null; 236 237 if (masters[k] == null) { 238 masters[k] = 239 findReflexiveMaster( 240 current, 241 (ObjRelationship) objEntity.getRelationship(reflexiveRelName), 242 current.getObjectId().getObjectClass()); 243 } 244 245 if (masters[k] != null) { 246 actualMasterCount++; 247 } 248 } 249 250 int mastersFound = 0; 251 for (int j = 0; j < size && mastersFound < actualMasterCount; j++) { 252 253 if (i == j) { 254 continue; 255 } 256 257 DataObject masterCandidate = (DataObject) objects.get(j); 258 for (int k = 0; k < masters.length; k++) { 259 if (masterCandidate.equals(masters[k])) { 260 objectDependencyGraph.putArc( 261 masterCandidate, 262 current, 263 Boolean.TRUE); 264 mastersFound++; 265 } 266 } 267 } 268 } 269 270 IndegreeTopologicalSort sorter = 271 new IndegreeTopologicalSort(objectDependencyGraph); 272 273 while (sorter.hasNext()) { 274 DataObject o = (DataObject) sorter.next(); 275 if (o == null) 276 throw new CayenneRuntimeException( 277 "Sorting objects for " 278 + objEntity.getClassName() 279 + " failed. Cycles found."); 280 sorted.add(o); 281 } 282 283 objects.clear(); 287 objects.addAll(sorted); 288 289 if (deleteOrder) { 290 Collections.reverse(objects); 291 } 292 } 293 294 protected void fillInMetadata(Table table, DbEntity entity) { 295 short keySequence = 1; 297 Iterator i = entity.getRelationshipMap().values().iterator(); 298 299 while (i.hasNext()) { 300 DbRelationship candidate = (DbRelationship) i.next(); 301 if ((!candidate.isToMany() && !candidate.isToDependentPK()) 302 || candidate.isToMasterPK()) { 303 DbEntity target = (DbEntity) candidate.getTargetEntity(); 304 boolean newReflexive = entity.equals(target); 305 Iterator j = candidate.getJoins().iterator(); 306 while (j.hasNext()) { 307 DbJoin join = (DbJoin) j.next(); 308 DbAttribute targetAttribute = join.getTarget(); 309 if (targetAttribute.isPrimaryKey()) { 310 ForeignKey fk = new ForeignKey(); 311 fk.setPkTableCatalog(target.getCatalog()); 312 fk.setPkTableSchema(target.getSchema()); 313 fk.setPkTableName(target.getName()); 314 fk.setPkColumnName(targetAttribute.getName()); 315 fk.setColumnName(join.getSourceName()); 316 fk.setKeySequence(keySequence++); 317 table.addForeignKey(fk); 318 319 if (newReflexive) { 320 List reflexiveRels = (List ) reflexiveDbEntities.get(entity); 321 if (reflexiveRels == null) { 322 reflexiveRels = new ArrayList (1); 323 reflexiveDbEntities.put(entity, reflexiveRels); 324 } 325 reflexiveRels.add(candidate); 326 newReflexive = false; 327 } 328 } 329 } 330 } 331 } 332 } 333 334 protected DataObject findReflexiveMaster( 335 DataObject object, 336 ObjRelationship toOneRel, 337 Class targetClass) { 338 DbRelationship finalRel = (DbRelationship) toOneRel.getDbRelationships().get(0); 339 340 DataRow snapshot = null; 341 342 if (object.getPersistenceState() != PersistenceState.NEW) { 344 DataContext context = object.getDataContext(); 345 snapshot = 346 context.getObjectStore().getSnapshot(object.getObjectId(), context); 347 } 348 349 if (snapshot == null) { 350 snapshot = object.getDataContext().currentSnapshot(object); 351 } 352 353 ObjectId id = snapshot.createTargetObjectId(targetClass, finalRel); 354 return (id != null) ? object.getDataContext().registeredObject(id) : null; 355 } 356 357 protected Comparator getDbEntityComparator(boolean dependantFirst) { 358 Comparator c = dbEntityComparator; 359 if (dependantFirst) { 360 c = new ReverseComparator(c); 361 } 362 return c; 363 } 364 365 protected Comparator getObjEntityComparator(boolean dependantFirst) { 366 Comparator c = objEntityComparator; 367 if (dependantFirst) { 368 c = new ReverseComparator(c); 369 } 370 return c; 371 } 372 373 protected Table getTable(DbEntity dbEntity) { 374 return (dbEntity != null) ? (Table) dbEntityToTableMap.get(dbEntity) : null; 375 } 376 377 protected Table getTable(ObjEntity objEntity) { 378 return getTable(objEntity.getDbEntity()); 379 } 380 381 protected boolean isReflexive(DbEntity metadata) { 382 return reflexiveDbEntities.containsKey(metadata); 383 } 384 385 private final class DbEntityComparator implements Comparator { 386 public int compare(Object o1, Object o2) { 387 if (o1 == o2) 388 return 0; 389 Table t1 = getTable((DbEntity) o1); 390 Table t2 = getTable((DbEntity) o2); 391 return tableComparator.compare(t1, t2); 392 } 393 } 394 395 private final class ObjEntityComparator implements Comparator { 396 public int compare(Object o1, Object o2) { 397 if (o1 == o2) 398 return 0; 399 Table t1 = getTable((ObjEntity) o1); 400 Table t2 = getTable((ObjEntity) o2); 401 return tableComparator.compare(t1, t2); 402 } 403 } 404 405 private final class TableComparator implements Comparator { 406 public int compare(Object o1, Object o2) { 407 int result = 0; 408 Table t1 = (Table) o1; 409 Table t2 = (Table) o2; 410 if (t1 == t2) 411 return 0; 412 if (t1 == null) 413 result = -1; 414 else if (t2 == null) 415 result = 1; 416 else { 417 ComponentRecord rec1 = (ComponentRecord) components.get(t1); 418 ComponentRecord rec2 = (ComponentRecord) components.get(t2); 419 int index1 = rec1.index; 420 int index2 = rec2.index; 421 result = (index1 > index2 ? 1 : (index1 < index2 ? -1 : 0)); 422 if (result != 0 && rec1.component == rec2.component) 423 result = 0; 424 } 425 return result; 426 } 427 } 428 429 private final static class ComponentRecord { 430 ComponentRecord(int index, Collection component) { 431 this.index = index; 432 this.component = component; 433 } 434 int index; 435 Collection component; 436 } 437 438 } | Popular Tags |