1 19 20 package org.apache.cayenne.access; 21 22 import java.sql.Connection ; 23 import java.sql.Driver ; 24 import java.sql.SQLException ; 25 import java.sql.Statement ; 26 import java.util.ArrayList ; 27 import java.util.Collection ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.ListIterator ; 33 import java.util.Map ; 34 35 import javax.sql.DataSource ; 36 37 import org.apache.cayenne.conn.DataSourceInfo; 38 import org.apache.cayenne.conn.DriverDataSource; 39 import org.apache.cayenne.dba.DbAdapter; 40 import org.apache.cayenne.dba.PkGenerator; 41 import org.apache.cayenne.dba.TypesMapping; 42 import org.apache.cayenne.map.DataMap; 43 import org.apache.cayenne.map.DbAttribute; 44 import org.apache.cayenne.map.DbEntity; 45 import org.apache.cayenne.map.DbJoin; 46 import org.apache.cayenne.map.DbRelationship; 47 import org.apache.cayenne.map.DerivedDbEntity; 48 import org.apache.cayenne.validation.SimpleValidationFailure; 49 import org.apache.cayenne.validation.ValidationResult; 50 import org.apache.commons.logging.Log; 51 import org.apache.commons.logging.LogFactory; 52 53 59 public class DbGenerator { 60 61 private Log logObj = LogFactory.getLog(DbGenerator.class); 62 63 protected DbAdapter adapter; 64 protected DataMap map; 65 66 protected DataDomain domain; 68 69 protected Map dropTables; 71 protected Map createTables; 72 protected Map createConstraints; 73 protected List createPK; 74 protected List dropPK; 75 76 80 protected List dbEntitiesInInsertOrder; 81 protected List dbEntitiesRequiringAutoPK; 82 83 protected boolean shouldDropTables; 84 protected boolean shouldCreateTables; 85 protected boolean shouldDropPKSupport; 86 protected boolean shouldCreatePKSupport; 87 protected boolean shouldCreateFKConstraints; 88 89 protected ValidationResult failures; 90 91 94 public DbGenerator(DbAdapter adapter, DataMap map) { 95 this(adapter, map, Collections.EMPTY_LIST); 96 } 97 98 105 public DbGenerator(DbAdapter adapter, DataMap map, Collection excludedEntities) { 106 this(adapter, map, excludedEntities, null); 107 } 108 109 118 public DbGenerator(DbAdapter adapter, DataMap map, Collection excludedEntities, 119 DataDomain domain) { 120 if (adapter == null) { 122 throw new IllegalArgumentException ("Adapter must not be null."); 123 } 124 125 if (map == null) { 126 throw new IllegalArgumentException ("DataMap must not be null."); 127 } 128 129 this.domain = domain; 130 this.map = map; 131 this.adapter = adapter; 132 133 prepareDbEntities(excludedEntities); 134 resetToDefaults(); 135 buildStatements(); 136 } 137 138 protected void resetToDefaults() { 139 this.shouldDropTables = false; 140 this.shouldDropPKSupport = false; 141 this.shouldCreatePKSupport = true; 142 this.shouldCreateTables = true; 143 this.shouldCreateFKConstraints = true; 144 } 145 146 151 protected void buildStatements() { 152 dropTables = new HashMap (); 153 createTables = new HashMap (); 154 createConstraints = new HashMap (); 155 156 DbAdapter adapter = getAdapter(); 157 Iterator it = dbEntitiesInInsertOrder.iterator(); 158 while (it.hasNext()) { 159 DbEntity dbe = (DbEntity) it.next(); 160 161 String name = dbe.getName(); 162 163 dropTables.put(name, adapter.dropTable(dbe)); 165 166 createTables.put(name, adapter.createTable(dbe)); 168 169 createConstraints.put(name, createConstraintsQueries(dbe)); 171 } 172 173 PkGenerator pkGenerator = adapter.getPkGenerator(); 174 dropPK = pkGenerator.dropAutoPkStatements(dbEntitiesRequiringAutoPK); 175 createPK = pkGenerator.createAutoPkStatements(dbEntitiesRequiringAutoPK); 176 } 177 178 184 public boolean isEmpty(boolean respectConfiguredSettings) { 185 if (dbEntitiesInInsertOrder.isEmpty() && dbEntitiesRequiringAutoPK.isEmpty()) { 186 return true; 187 } 188 189 if (!respectConfiguredSettings) { 190 return false; 191 } 192 193 return !(shouldDropTables 194 || shouldCreateTables 195 || shouldCreateFKConstraints 196 || shouldCreatePKSupport || shouldDropPKSupport); 197 } 198 199 200 public DbAdapter getAdapter() { 201 return adapter; 202 } 203 204 208 public List configuredStatements() { 209 List list = new ArrayList (); 210 211 if (shouldDropTables) { 212 ListIterator it = dbEntitiesInInsertOrder 213 .listIterator(dbEntitiesInInsertOrder.size()); 214 while (it.hasPrevious()) { 215 DbEntity ent = (DbEntity) it.previous(); 216 list.add(dropTables.get(ent.getName())); 217 } 218 } 219 220 if (shouldCreateTables) { 221 Iterator it = dbEntitiesInInsertOrder.iterator(); 222 while (it.hasNext()) { 223 DbEntity ent = (DbEntity) it.next(); 224 list.add(createTables.get(ent.getName())); 225 } 226 } 227 228 if (shouldCreateFKConstraints) { 229 Iterator it = dbEntitiesInInsertOrder.iterator(); 230 while (it.hasNext()) { 231 DbEntity ent = (DbEntity) it.next(); 232 List fks = (List ) createConstraints.get(ent.getName()); 233 list.addAll(fks); 234 } 235 } 236 237 if (shouldDropPKSupport) { 238 list.addAll(dropPK); 239 } 240 241 if (shouldCreatePKSupport) { 242 list.addAll(createPK); 243 } 244 245 return list; 246 } 247 248 252 public void runGenerator(DataSourceInfo dsi) throws Exception { 253 this.failures = null; 254 255 if (isEmpty(true)) { 258 return; 259 } 260 261 Driver driver = (Driver ) Class.forName(dsi.getJdbcDriver()).newInstance(); 262 DataSource dataSource = new DriverDataSource(driver, dsi.getDataSourceUrl(), dsi 263 .getUserName(), dsi.getPassword()); 264 265 runGenerator(dataSource); 266 } 267 268 273 public void runGenerator(DataSource ds) throws Exception { 274 this.failures = null; 275 276 Connection connection = ds.getConnection(); 277 278 try { 279 280 if (shouldDropTables) { 282 ListIterator it = dbEntitiesInInsertOrder 283 .listIterator(dbEntitiesInInsertOrder.size()); 284 while (it.hasPrevious()) { 285 DbEntity ent = (DbEntity) it.previous(); 286 safeExecute(connection, (String ) dropTables.get(ent.getName())); 287 } 288 } 289 290 List createdTables = new ArrayList (); 292 if (shouldCreateTables) { 293 Iterator it = dbEntitiesInInsertOrder.iterator(); 294 while (it.hasNext()) { 295 DbEntity ent = (DbEntity) it.next(); 296 297 299 safeExecute(connection, (String ) createTables.get(ent.getName())); 300 createdTables.add(ent.getName()); 301 } 302 } 303 304 if (shouldCreateTables && shouldCreateFKConstraints) { 306 Iterator it = dbEntitiesInInsertOrder.iterator(); 307 while (it.hasNext()) { 308 DbEntity ent = (DbEntity) it.next(); 309 310 if (createdTables.contains(ent.getName())) { 311 List fks = (List ) createConstraints.get(ent.getName()); 312 Iterator fkIt = fks.iterator(); 313 while (fkIt.hasNext()) { 314 safeExecute(connection, (String ) fkIt.next()); 315 } 316 } 317 } 318 } 319 320 if (shouldDropPKSupport) { 322 List dropAutoPKSQL = getAdapter().getPkGenerator().dropAutoPkStatements( 323 dbEntitiesRequiringAutoPK); 324 Iterator it = dropAutoPKSQL.iterator(); 325 while (it.hasNext()) { 326 safeExecute(connection, (String ) it.next()); 327 } 328 } 329 330 if (shouldCreatePKSupport) { 332 List createAutoPKSQL = getAdapter() 333 .getPkGenerator() 334 .createAutoPkStatements(dbEntitiesRequiringAutoPK); 335 Iterator it = createAutoPKSQL.iterator(); 336 while (it.hasNext()) { 337 safeExecute(connection, (String ) it.next()); 338 } 339 } 340 341 new DbGeneratorPostprocessor().execute(connection); 342 } 343 finally { 344 connection.close(); 345 } 346 } 347 348 354 protected boolean safeExecute(Connection connection, String sql) throws SQLException { 355 Statement statement = connection.createStatement(); 356 357 try { 358 QueryLogger.logQuery(sql, null); 359 statement.execute(sql); 360 return true; 361 } 362 catch (SQLException ex) { 363 if (this.failures == null) { 364 this.failures = new ValidationResult(); 365 } 366 367 failures.addFailure(new SimpleValidationFailure(sql, ex.getMessage())); 368 QueryLogger.logQueryError(ex); 369 return false; 370 } 371 finally { 372 statement.close(); 373 } 374 } 375 376 383 public List createFkConstraintsQueries(DbEntity table) { 384 return createConstraintsQueries(table); 385 } 386 387 392 public List createConstraintsQueries(DbEntity table) { 393 List list = new ArrayList (); 394 Iterator it = table.getRelationships().iterator(); 395 while (it.hasNext()) { 396 DbRelationship rel = (DbRelationship) it.next(); 397 398 if (rel.isToMany()) { 399 continue; 400 } 401 402 if (domain != null) { 404 DataMap srcMap = rel.getSourceEntity().getDataMap(); 405 DataMap targetMap = rel.getTargetEntity().getDataMap(); 406 407 if (srcMap != null && targetMap != null && srcMap != targetMap) { 408 if (domain.lookupDataNode(srcMap) != domain.lookupDataNode(targetMap)) { 409 continue; 410 } 411 } 412 } 413 414 417 419 if (rel.isToPK() && !rel.isToDependentPK()) { 420 421 if (getAdapter().supportsUniqueConstraints()) { 422 423 DbRelationship reverse = rel.getReverseRelationship(); 424 if (reverse != null && !reverse.isToMany() && !reverse.isToPK()) { 425 list.add(getAdapter().createUniqueConstraint( 426 (DbEntity) rel.getSourceEntity(), 427 rel.getSourceAttributes())); 428 } 429 } 430 431 String fk = getAdapter().createFkConstraint(rel); 432 if (fk != null) { 433 list.add(fk); 434 } 435 } 436 } 437 return list; 438 } 439 440 448 public ValidationResult getFailures() { 449 return failures; 450 } 451 452 456 public boolean shouldCreatePKSupport() { 457 return shouldCreatePKSupport; 458 } 459 460 463 public boolean shouldCreateTables() { 464 return shouldCreateTables; 465 } 466 467 public boolean shouldDropPKSupport() { 468 return shouldDropPKSupport; 469 } 470 471 public boolean shouldDropTables() { 472 return shouldDropTables; 473 } 474 475 public boolean shouldCreateFKConstraints() { 476 return shouldCreateFKConstraints; 477 } 478 479 public void setShouldCreatePKSupport(boolean shouldCreatePKSupport) { 480 this.shouldCreatePKSupport = shouldCreatePKSupport; 481 } 482 483 public void setShouldCreateTables(boolean shouldCreateTables) { 484 this.shouldCreateTables = shouldCreateTables; 485 } 486 487 public void setShouldDropPKSupport(boolean shouldDropPKSupport) { 488 this.shouldDropPKSupport = shouldDropPKSupport; 489 } 490 491 public void setShouldDropTables(boolean shouldDropTables) { 492 this.shouldDropTables = shouldDropTables; 493 } 494 495 public void setShouldCreateFKConstraints(boolean shouldCreateFKConstraints) { 496 this.shouldCreateFKConstraints = shouldCreateFKConstraints; 497 } 498 499 505 public DataDomain getDomain() { 506 return domain; 507 } 508 509 513 private void prepareDbEntities(Collection excludedEntities) { 514 if (excludedEntities == null) { 515 excludedEntities = Collections.EMPTY_LIST; 516 } 517 518 List tables = new ArrayList (); 520 List tablesWithAutoPk = new ArrayList (); 521 Iterator it = map.getDbEntities().iterator(); 522 while (it.hasNext()) { 523 DbEntity nextEntity = (DbEntity) it.next(); 524 525 527 if (nextEntity instanceof DerivedDbEntity) { 529 continue; 530 } 531 532 if (nextEntity.getAttributes().size() == 0) { 534 logObj 535 .info("Skipping entity with no attributes: " 536 + nextEntity.getName()); 537 continue; 538 } 539 540 if (excludedEntities.contains(nextEntity)) { 542 continue; 543 } 544 545 boolean invalidAttributes = false; 547 Iterator nextDbAtributes = nextEntity.getAttributes().iterator(); 548 while (nextDbAtributes.hasNext()) { 549 DbAttribute attr = (DbAttribute) nextDbAtributes.next(); 550 if (attr.getType() == TypesMapping.NOT_DEFINED) { 551 logObj.info("Skipping entity, attribute type is undefined: " 552 + nextEntity.getName() 553 + "." 554 + attr.getName()); 555 invalidAttributes = true; 556 break; 557 } 558 } 559 if (invalidAttributes) { 560 continue; 561 } 562 563 tables.add(nextEntity); 564 565 Iterator relationships = nextEntity.getRelationships().iterator(); 568 569 List pkAttributes = new ArrayList (nextEntity.getPrimaryKey()); 572 while (pkAttributes.size() > 0 && relationships.hasNext()) { 573 DbRelationship nextRelationship = (DbRelationship) relationships.next(); 574 if (!nextRelationship.isToMasterPK()) { 575 continue; 576 } 577 578 Iterator joins = nextRelationship.getJoins().iterator(); 582 while (joins.hasNext()) { 583 DbJoin join = (DbJoin) joins.next(); 584 pkAttributes.remove(join.getSource()); 585 } 586 } 587 588 if (pkAttributes.size() > 0) { 591 tablesWithAutoPk.add(nextEntity); 592 } 593 } 594 595 if (tables.size() > 1) { 597 DataNode node = new DataNode("temp"); 598 node.addDataMap(map); 599 node.getEntitySorter().sortDbEntities(tables, false); 600 } 601 602 this.dbEntitiesInInsertOrder = tables; 603 this.dbEntitiesRequiringAutoPK = tablesWithAutoPk; 604 } 605 } 606 | Popular Tags |