1 56 57 package org.objectstyle.cayenne.access; 58 59 import java.sql.Connection ; 60 import java.sql.Driver ; 61 import java.sql.SQLException ; 62 import java.sql.Statement ; 63 import java.util.ArrayList ; 64 import java.util.Collection ; 65 import java.util.Collections ; 66 import java.util.HashMap ; 67 import java.util.Iterator ; 68 import java.util.List ; 69 import java.util.ListIterator ; 70 import java.util.Map ; 71 72 import javax.sql.DataSource ; 73 74 import org.apache.log4j.Level; 75 import org.apache.log4j.Logger; 76 import org.objectstyle.cayenne.CayenneRuntimeException; 77 import org.objectstyle.cayenne.conn.DataSourceInfo; 78 import org.objectstyle.cayenne.conn.DriverDataSource; 79 import org.objectstyle.cayenne.dba.DbAdapter; 80 import org.objectstyle.cayenne.dba.PkGenerator; 81 import org.objectstyle.cayenne.dba.TypesMapping; 82 import org.objectstyle.cayenne.map.DataMap; 83 import org.objectstyle.cayenne.map.DbAttribute; 84 import org.objectstyle.cayenne.map.DbEntity; 85 import org.objectstyle.cayenne.map.DbJoin; 86 import org.objectstyle.cayenne.map.DbRelationship; 87 import org.objectstyle.cayenne.map.DerivedDbEntity; 88 import org.objectstyle.cayenne.validation.SimpleValidationFailure; 89 import org.objectstyle.cayenne.validation.ValidationResult; 90 91 97 public class DbGenerator { 98 99 private Logger logObj = Logger.getLogger(DbGenerator.class); 100 101 protected DbAdapter adapter; 102 protected DataMap map; 103 104 protected Map dropTables; 106 protected Map createTables; 107 protected Map createFK; 108 protected List createPK; 109 protected List dropPK; 110 111 115 protected List dbEntitiesInInsertOrder; 116 protected List dbEntitiesRequiringAutoPK; 117 118 protected boolean shouldDropTables; 119 protected boolean shouldCreateTables; 120 protected boolean shouldDropPKSupport; 121 protected boolean shouldCreatePKSupport; 122 protected boolean shouldCreateFKConstraints; 123 124 protected ValidationResult failures; 125 126 129 public DbGenerator(DbAdapter adapter, DataMap map) { 130 this(adapter, map, Collections.EMPTY_LIST); 131 } 132 133 137 public DbGenerator(DbAdapter adapter, DataMap map, Collection excludedEntities) { 138 if (adapter == null) { 140 throw new IllegalArgumentException ("Adapter must not be null."); 141 } 142 143 if (map == null) { 144 throw new IllegalArgumentException ("DataMap must not be null."); 145 } 146 147 this.map = map; 148 this.adapter = adapter; 149 150 prepareDbEntities(excludedEntities); 151 resetToDefaults(); 152 buildStatements(); 153 } 154 155 protected void resetToDefaults() { 156 this.shouldDropTables = false; 157 this.shouldDropPKSupport = false; 158 this.shouldCreatePKSupport = true; 159 this.shouldCreateTables = true; 160 this.shouldCreateFKConstraints = true; 161 } 162 163 168 protected void buildStatements() { 169 dropTables = new HashMap (); 170 createTables = new HashMap (); 171 createFK = new HashMap (); 172 173 DbAdapter adapter = getAdapter(); 174 Iterator it = dbEntitiesInInsertOrder.iterator(); 175 boolean supportsFK = adapter.supportsFkConstraints(); 176 while (it.hasNext()) { 177 DbEntity dbe = (DbEntity) it.next(); 178 179 String name = dbe.getName(); 180 181 dropTables.put(name, adapter.dropTable(dbe)); 183 184 createTables.put(name, adapter.createTable(dbe)); 186 187 if (supportsFK) { 189 createFK.put(name, createFkConstraintsQueries(dbe)); 190 } 191 } 192 193 PkGenerator pkGenerator = adapter.getPkGenerator(); 194 dropPK = pkGenerator.dropAutoPkStatements(dbEntitiesRequiringAutoPK); 195 createPK = pkGenerator.createAutoPkStatements(dbEntitiesRequiringAutoPK); 196 } 197 198 204 public boolean isEmpty(boolean respectConfiguredSettings) { 205 if (dbEntitiesInInsertOrder.isEmpty() && dbEntitiesRequiringAutoPK.isEmpty()) { 206 return true; 207 } 208 209 if (!respectConfiguredSettings) { 210 return false; 211 } 212 213 return !(shouldDropTables 214 || shouldCreateTables 215 || shouldCreateFKConstraints 216 || shouldCreatePKSupport || shouldDropPKSupport); 217 } 218 219 220 public DbAdapter getAdapter() { 221 return adapter; 222 } 223 224 228 public List configuredStatements() { 229 List list = new ArrayList (); 230 231 if (shouldDropTables) { 232 ListIterator it = dbEntitiesInInsertOrder 233 .listIterator(dbEntitiesInInsertOrder.size()); 234 while (it.hasPrevious()) { 235 DbEntity ent = (DbEntity) it.previous(); 236 list.add(dropTables.get(ent.getName())); 237 } 238 } 239 240 if (shouldCreateTables) { 241 Iterator it = dbEntitiesInInsertOrder.iterator(); 242 while (it.hasNext()) { 243 DbEntity ent = (DbEntity) it.next(); 244 list.add(createTables.get(ent.getName())); 245 } 246 } 247 248 if (shouldCreateFKConstraints && getAdapter().supportsFkConstraints()) { 249 Iterator it = dbEntitiesInInsertOrder.iterator(); 250 while (it.hasNext()) { 251 DbEntity ent = (DbEntity) it.next(); 252 List fks = (List ) createFK.get(ent.getName()); 253 list.addAll(fks); 254 } 255 } 256 257 if (shouldDropPKSupport) { 258 list.addAll(dropPK); 259 } 260 261 if (shouldCreatePKSupport) { 262 list.addAll(createPK); 263 } 264 265 return list; 266 } 267 268 272 public void runGenerator(DataSourceInfo dsi) throws Exception { 273 this.failures = null; 274 275 if (isEmpty(true)) { 278 return; 279 } 280 281 Driver driver = (Driver ) Class.forName(dsi.getJdbcDriver()).newInstance(); 282 DataSource dataSource = new DriverDataSource(driver, dsi.getDataSourceUrl(), dsi 283 .getUserName(), dsi.getPassword()); 284 285 runGenerator(dataSource); 286 } 287 288 293 public void runGenerator(DataSource ds) throws Exception { 294 this.failures = null; 295 296 Connection connection = ds.getConnection(); 297 298 try { 299 300 if (shouldDropTables) { 302 ListIterator it = dbEntitiesInInsertOrder 303 .listIterator(dbEntitiesInInsertOrder.size()); 304 while (it.hasPrevious()) { 305 DbEntity ent = (DbEntity) it.previous(); 306 safeExecute(connection, (String ) dropTables.get(ent.getName())); 307 } 308 } 309 310 List createdTables = new ArrayList (); 312 if (shouldCreateTables) { 313 Iterator it = dbEntitiesInInsertOrder.iterator(); 314 while (it.hasNext()) { 315 DbEntity ent = (DbEntity) it.next(); 316 317 319 safeExecute(connection, (String ) createTables.get(ent.getName())); 320 createdTables.add(ent.getName()); 321 } 322 } 323 324 if (shouldCreateTables 326 && shouldCreateFKConstraints 327 && getAdapter().supportsFkConstraints()) { 328 Iterator it = dbEntitiesInInsertOrder.iterator(); 329 while (it.hasNext()) { 330 DbEntity ent = (DbEntity) it.next(); 331 332 if (createdTables.contains(ent.getName())) { 333 List fks = (List ) createFK.get(ent.getName()); 334 Iterator fkIt = fks.iterator(); 335 while (fkIt.hasNext()) { 336 safeExecute(connection, (String ) fkIt.next()); 337 } 338 } 339 } 340 } 341 342 if (shouldDropPKSupport) { 344 List dropAutoPKSQL = getAdapter().getPkGenerator().dropAutoPkStatements( 345 dbEntitiesRequiringAutoPK); 346 Iterator it = dropAutoPKSQL.iterator(); 347 while (it.hasNext()) { 348 safeExecute(connection, (String ) it.next()); 349 } 350 } 351 352 if (shouldCreatePKSupport) { 354 List createAutoPKSQL = getAdapter() 355 .getPkGenerator() 356 .createAutoPkStatements(dbEntitiesRequiringAutoPK); 357 Iterator it = createAutoPKSQL.iterator(); 358 while (it.hasNext()) { 359 safeExecute(connection, (String ) it.next()); 360 } 361 } 362 } 363 finally { 364 connection.close(); 365 } 366 } 367 368 374 protected boolean safeExecute(Connection connection, String sql) throws SQLException { 375 Statement statement = connection.createStatement(); 376 377 try { 378 QueryLogger.logQuery(Level.INFO, sql, null); 379 statement.execute(sql); 380 return true; 381 } 382 catch (SQLException ex) { 383 if (this.failures == null) { 384 this.failures = new ValidationResult(); 385 } 386 387 failures.addFailure(new SimpleValidationFailure(sql, ex.getMessage())); 388 QueryLogger.logQueryError(Level.INFO, ex); 389 return false; 390 } 391 finally { 392 statement.close(); 393 } 394 } 395 396 401 public List createFkConstraintsQueries(DbEntity dbEnt) { 402 if (!getAdapter().supportsFkConstraints()) { 403 throw new CayenneRuntimeException( 404 "FK constraints are not supported by adapter."); 405 } 406 407 List list = new ArrayList (); 408 Iterator it = dbEnt.getRelationships().iterator(); 409 while (it.hasNext()) { 410 DbRelationship rel = (DbRelationship) it.next(); 411 412 if (rel.isToMany()) { 413 continue; 414 } 415 416 419 421 if (rel.isToPK() && !rel.isToDependentPK()) { 422 423 if (getAdapter().supportsUniqueConstraints()) { 424 425 DbRelationship reverse = rel.getReverseRelationship(); 426 if (reverse != null && !reverse.isToMany() && !reverse.isToPK()) { 427 list.add(getAdapter().createUniqueConstraint( 428 (DbEntity) rel.getSourceEntity(), 429 rel.getSourceAttributes())); 430 } 431 } 432 433 list.add(getAdapter().createFkConstraint(rel)); 434 } 435 } 436 return list; 437 } 438 439 447 public ValidationResult getFailures() { 448 return failures; 449 } 450 451 455 public boolean shouldCreatePKSupport() { 456 return shouldCreatePKSupport; 457 } 458 459 462 public boolean shouldCreateTables() { 463 return shouldCreateTables; 464 } 465 466 public boolean shouldDropPKSupport() { 467 return shouldDropPKSupport; 468 } 469 470 public boolean shouldDropTables() { 471 return shouldDropTables; 472 } 473 474 public boolean shouldCreateFKConstraints() { 475 return shouldCreateFKConstraints; 476 } 477 478 public void setShouldCreatePKSupport(boolean shouldCreatePKSupport) { 479 this.shouldCreatePKSupport = shouldCreatePKSupport; 480 } 481 482 public void setShouldCreateTables(boolean shouldCreateTables) { 483 this.shouldCreateTables = shouldCreateTables; 484 } 485 486 public void setShouldDropPKSupport(boolean shouldDropPKSupport) { 487 this.shouldDropPKSupport = shouldDropPKSupport; 488 } 489 490 public void setShouldDropTables(boolean shouldDropTables) { 491 this.shouldDropTables = shouldDropTables; 492 } 493 494 public void setShouldCreateFKConstraints(boolean shouldCreateFKConstraints) { 495 this.shouldCreateFKConstraints = shouldCreateFKConstraints; 496 } 497 498 502 private void prepareDbEntities(Collection excludedEntities) { 503 if (excludedEntities == null) { 504 excludedEntities = Collections.EMPTY_LIST; 505 } 506 507 List tables = new ArrayList (); 509 List tablesWithAutoPk = new ArrayList (); 510 Iterator it = map.getDbEntities().iterator(); 511 while (it.hasNext()) { 512 DbEntity nextEntity = (DbEntity) it.next(); 513 514 516 if (nextEntity instanceof DerivedDbEntity) { 518 continue; 519 } 520 521 if (nextEntity.getAttributes().size() == 0) { 523 logObj 524 .info("Skipping entity with no attributes: " 525 + nextEntity.getName()); 526 continue; 527 } 528 529 if (excludedEntities.contains(nextEntity)) { 531 continue; 532 } 533 534 boolean invalidAttributes = false; 536 Iterator nextDbAtributes = nextEntity.getAttributes().iterator(); 537 while (nextDbAtributes.hasNext()) { 538 DbAttribute attr = (DbAttribute) nextDbAtributes.next(); 539 if (attr.getType() == TypesMapping.NOT_DEFINED) { 540 logObj.info("Skipping entity, attribute type is undefined: " 541 + nextEntity.getName() 542 + "." 543 + attr.getName()); 544 invalidAttributes = true; 545 break; 546 } 547 } 548 if (invalidAttributes) { 549 continue; 550 } 551 552 tables.add(nextEntity); 553 554 Iterator relationships = nextEntity.getRelationships().iterator(); 557 558 List pkAttributes = new ArrayList (nextEntity.getPrimaryKey()); 561 while (pkAttributes.size() > 0 && relationships.hasNext()) { 562 DbRelationship nextRelationship = (DbRelationship) relationships.next(); 563 if (!nextRelationship.isToMasterPK()) { 564 continue; 565 } 566 567 Iterator joins = nextRelationship.getJoins().iterator(); 571 while (joins.hasNext()) { 572 DbJoin join = (DbJoin) joins.next(); 573 pkAttributes.remove(join.getSource()); 574 } 575 } 576 577 if (pkAttributes.size() > 0) { 580 tablesWithAutoPk.add(nextEntity); 581 } 582 } 583 584 if (tables.size() > 1) { 586 DataNode node = new DataNode("temp"); 587 node.addDataMap(map); 588 node.getEntitySorter().sortDbEntities(tables, false); 589 } 590 591 this.dbEntitiesInInsertOrder = tables; 592 this.dbEntitiesRequiringAutoPK = tablesWithAutoPk; 593 } 594 } | Popular Tags |