1 56 57 package org.objectstyle.cayenne.dba; 58 59 import java.net.URL ; 60 import java.sql.Connection ; 61 import java.sql.PreparedStatement ; 62 import java.sql.SQLException ; 63 import java.util.Collection ; 64 import java.util.Iterator ; 65 66 import org.objectstyle.cayenne.CayenneRuntimeException; 67 import org.objectstyle.cayenne.access.DataNode; 68 import org.objectstyle.cayenne.access.OperationObserver; 69 import org.objectstyle.cayenne.access.QueryTranslator; 70 import org.objectstyle.cayenne.access.trans.DeleteTranslator; 71 import org.objectstyle.cayenne.access.trans.ProcedureTranslator; 72 import org.objectstyle.cayenne.access.trans.QualifierTranslator; 73 import org.objectstyle.cayenne.access.trans.QueryAssembler; 74 import org.objectstyle.cayenne.access.trans.SelectTranslator; 75 import org.objectstyle.cayenne.access.trans.UpdateTranslator; 76 import org.objectstyle.cayenne.access.types.BooleanType; 77 import org.objectstyle.cayenne.access.types.ByteArrayType; 78 import org.objectstyle.cayenne.access.types.CharType; 79 import org.objectstyle.cayenne.access.types.ExtendedType; 80 import org.objectstyle.cayenne.access.types.ExtendedTypeMap; 81 import org.objectstyle.cayenne.access.types.UtilDateType; 82 import org.objectstyle.cayenne.map.DbAttribute; 83 import org.objectstyle.cayenne.map.DbEntity; 84 import org.objectstyle.cayenne.map.DbJoin; 85 import org.objectstyle.cayenne.map.DbRelationship; 86 import org.objectstyle.cayenne.map.DerivedDbEntity; 87 import org.objectstyle.cayenne.query.BatchQuery; 88 import org.objectstyle.cayenne.query.DeleteQuery; 89 import org.objectstyle.cayenne.query.ProcedureQuery; 90 import org.objectstyle.cayenne.query.Query; 91 import org.objectstyle.cayenne.query.SQLAction; 92 import org.objectstyle.cayenne.query.SelectQuery; 93 import org.objectstyle.cayenne.query.UpdateQuery; 94 import org.objectstyle.cayenne.util.ResourceLocator; 95 import org.objectstyle.cayenne.util.Util; 96 97 103 public class JdbcAdapter implements DbAdapter { 104 105 protected PkGenerator pkGenerator; 106 protected TypesHandler typesHandler; 107 protected ExtendedTypeMap extendedTypes; 108 protected boolean supportsBatchUpdates; 109 protected boolean supportsFkConstraints; 110 protected boolean supportsUniqueConstraints; 111 protected boolean supportsGeneratedKeys; 112 113 116 public JdbcAdapter() { 117 this.setSupportsBatchUpdates(false); 119 this.setSupportsUniqueConstraints(true); 120 this.setSupportsFkConstraints(true); 121 122 this.pkGenerator = this.createPkGenerator(); 123 this.typesHandler = TypesHandler.getHandler(findAdapterResource("/types.xml")); 124 this.extendedTypes = new ExtendedTypeMap(); 125 this.configureExtendedTypes(extendedTypes); 126 } 127 128 133 public String getBatchTerminator() { 134 return ";"; 135 } 136 137 148 public URL findAdapterResource(String name) { 149 Class adapterClass = this.getClass(); 150 151 while (adapterClass != null && JdbcAdapter.class.isAssignableFrom(adapterClass)) { 152 153 String path = Util.getPackagePath(adapterClass.getName()) + name; 154 URL url = ResourceLocator.findURLInClasspath(path); 155 if (url != null) { 156 return url; 157 } 158 159 adapterClass = adapterClass.getSuperclass(); 160 } 161 162 return null; 163 } 164 165 169 protected void configureExtendedTypes(ExtendedTypeMap map) { 170 map.registerType(new BooleanType()); 173 174 map.registerType(new CharType(false, true)); 178 179 map.registerType(new UtilDateType()); 181 182 map.registerType(new ByteArrayType(false, true)); 184 } 185 186 191 protected PkGenerator createPkGenerator() { 192 return new JdbcPkGenerator(); 193 } 194 195 198 public PkGenerator getPkGenerator() { 199 return pkGenerator; 200 } 201 202 207 public void setPkGenerator(PkGenerator pkGenerator) { 208 this.pkGenerator = pkGenerator; 209 } 210 211 215 public QueryTranslator getQueryTranslator(Query query) throws Exception { 216 Class queryClass = queryTranslatorClass(query); 217 218 try { 219 QueryTranslator t = (QueryTranslator) queryClass.newInstance(); 220 t.setQuery(query); 221 t.setAdapter(this); 222 return t; 223 } 224 catch (Exception ex) { 225 throw new CayenneRuntimeException("Can't load translator class: " 226 + queryClass); 227 } 228 } 229 230 238 protected Class queryTranslatorClass(Query q) { 239 if (q == null) { 240 throw new NullPointerException ("Null query."); 241 } 242 else if (q instanceof SelectQuery) { 243 return SelectTranslator.class; 244 } 245 else if (q instanceof UpdateQuery) { 246 return UpdateTranslator.class; 247 } 248 else if (q instanceof org.objectstyle.cayenne.query.InsertQuery) { 249 return org.objectstyle.cayenne.access.trans.InsertTranslator.class; 250 } 251 else if (q instanceof DeleteQuery) { 252 return DeleteTranslator.class; 253 } 254 else if (q instanceof ProcedureQuery) { 255 return ProcedureTranslator.class; 256 } 257 else { 258 throw new CayenneRuntimeException("Unrecognized query class..." 259 + q.getClass().getName()); 260 } 261 } 262 263 266 public boolean supportsFkConstraints() { 267 return supportsFkConstraints; 268 } 269 270 273 public void setSupportsFkConstraints(boolean flag) { 274 this.supportsFkConstraints = flag; 275 } 276 277 282 public boolean supportsUniqueConstraints() { 283 return supportsUniqueConstraints; 284 } 285 286 289 public void setSupportsUniqueConstraints(boolean flag) { 290 this.supportsUniqueConstraints = flag; 291 } 292 293 296 public String dropTable(DbEntity ent) { 297 return "DROP TABLE " + ent.getFullyQualifiedName(); 298 } 299 300 304 public String createTable(DbEntity ent) { 305 if (ent instanceof DerivedDbEntity) { 308 throw new CayenneRuntimeException("Can't create table for derived DbEntity '" 309 + ent.getName() 310 + "'."); 311 } 312 313 StringBuffer sqlBuffer = new StringBuffer (); 314 sqlBuffer 315 .append("CREATE TABLE ") 316 .append(ent.getFullyQualifiedName()) 317 .append(" ("); 318 319 Iterator it = ent.getAttributes().iterator(); 321 boolean first = true; 322 while (it.hasNext()) { 323 if (first) { 324 first = false; 325 } 326 else { 327 sqlBuffer.append(", "); 328 } 329 330 DbAttribute column = (DbAttribute) it.next(); 331 332 if (column.getType() == TypesMapping.NOT_DEFINED) { 334 throw new CayenneRuntimeException("Undefined type for attribute '" 335 + ent.getFullyQualifiedName() 336 + "." 337 + column.getName() 338 + "'."); 339 } 340 341 createTableAppendColumn(sqlBuffer, column); 342 343 } 344 345 Iterator pkit = ent.getPrimaryKey().iterator(); 347 if (pkit.hasNext()) { 348 if (first) 349 first = false; 350 else 351 sqlBuffer.append(", "); 352 353 sqlBuffer.append("PRIMARY KEY ("); 354 boolean firstPk = true; 355 while (pkit.hasNext()) { 356 if (firstPk) 357 firstPk = false; 358 else 359 sqlBuffer.append(", "); 360 361 DbAttribute at = (DbAttribute) pkit.next(); 362 sqlBuffer.append(at.getName()); 363 } 364 sqlBuffer.append(')'); 365 } 366 sqlBuffer.append(')'); 367 368 return sqlBuffer.toString(); 369 } 370 371 376 protected void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column) { 377 String [] types = externalTypesForJdbcType(column.getType()); 378 if (types == null || types.length == 0) { 379 String entityName = column.getEntity() != null ? ((DbEntity) column 380 .getEntity()).getFullyQualifiedName() : "<null>"; 381 throw new CayenneRuntimeException("Undefined type for attribute '" 382 + entityName 383 + "." 384 + column.getName() 385 + "': " 386 + column.getType()); 387 } 388 389 String type = types[0]; 390 sqlBuffer.append(column.getName()).append(' ').append(type); 391 392 if (TypesMapping.supportsLength(column.getType())) { 394 int len = column.getMaxLength(); 395 int prec = TypesMapping.isDecimal(column.getType()) 396 ? column.getPrecision() 397 : -1; 398 399 if (prec > len) { 401 prec = -1; 402 } 403 404 if (len > 0) { 405 sqlBuffer.append('(').append(len); 406 407 if (prec >= 0) { 408 sqlBuffer.append(", ").append(prec); 409 } 410 411 sqlBuffer.append(')'); 412 } 413 } 414 415 sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL"); 416 } 417 418 423 public String createUniqueConstraint(DbEntity source, Collection columns) { 424 if (columns == null || columns.isEmpty()) { 425 throw new CayenneRuntimeException( 426 "Can't create UNIQUE constraint - no columns specified."); 427 } 428 429 StringBuffer buf = new StringBuffer (); 430 431 buf 432 .append("ALTER TABLE ") 433 .append(source.getFullyQualifiedName()) 434 .append(" ADD UNIQUE ("); 435 436 Iterator it = columns.iterator(); 437 DbAttribute first = (DbAttribute) it.next(); 438 buf.append(first.getName()); 439 440 while (it.hasNext()) { 441 DbAttribute next = (DbAttribute) it.next(); 442 buf.append(", "); 443 buf.append(next.getName()); 444 } 445 446 buf.append(")"); 447 448 return buf.toString(); 449 } 450 451 455 public String createFkConstraint(DbRelationship rel) { 456 StringBuffer buf = new StringBuffer (); 457 StringBuffer refBuf = new StringBuffer (); 458 459 buf.append("ALTER TABLE ").append(((DbEntity) rel.getSourceEntity()) 460 .getFullyQualifiedName()).append(" ADD FOREIGN KEY ("); 461 462 Iterator jit = rel.getJoins().iterator(); 463 boolean first = true; 464 while (jit.hasNext()) { 465 DbJoin join = (DbJoin) jit.next(); 466 if (!first) { 467 buf.append(", "); 468 refBuf.append(", "); 469 } 470 else 471 first = false; 472 473 buf.append(join.getSourceName()); 474 refBuf.append(join.getTargetName()); 475 } 476 477 buf 478 .append(") REFERENCES ") 479 .append(((DbEntity) rel.getTargetEntity()).getFullyQualifiedName()) 480 .append(" (") 481 .append(refBuf.toString()) 482 .append(')'); 483 return buf.toString(); 484 } 485 486 public String [] externalTypesForJdbcType(int type) { 487 return typesHandler.externalTypesForJdbcType(type); 488 } 489 490 public ExtendedTypeMap getExtendedTypes() { 491 return extendedTypes; 492 } 493 494 public DbAttribute buildAttribute( 495 String name, 496 String typeName, 497 int type, 498 int size, 499 int precision, 500 boolean allowNulls) { 501 502 DbAttribute attr = new DbAttribute(); 503 attr.setName(name); 504 attr.setType(type); 505 attr.setMandatory(!allowNulls); 506 507 if (size >= 0) { 508 attr.setMaxLength(size); 509 } 510 511 if (precision >= 0) { 512 attr.setPrecision(precision); 513 } 514 515 return attr; 516 } 517 518 public String tableTypeForTable() { 519 return "TABLE"; 520 } 521 522 public String tableTypeForView() { 523 return "VIEW"; 524 } 525 526 529 public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { 530 return new QualifierTranslator(queryAssembler); 531 } 532 533 539 public DataNode createDataNode(String name) { 540 DataNode node = new DataNode(name); 541 node.setAdapter(this); 542 return node; 543 } 544 545 550 public SQLAction getAction(Query query, DataNode node) { 551 return query.createSQLAction(new JdbcActionBuilder(this, node.getEntityResolver())); 552 } 553 554 public void bindParameter( 555 PreparedStatement statement, 556 Object object, 557 int pos, 558 int sqlType, 559 int precision) throws SQLException , Exception { 560 561 if (object == null) { 562 statement.setNull(pos, sqlType); 563 } 564 else { 565 ExtendedType typeProcessor = getExtendedTypes().getRegisteredType(object 566 .getClass()); 567 typeProcessor.setJdbcObject(statement, object, pos, sqlType, precision); 568 } 569 } 570 571 public boolean supportsBatchUpdates() { 572 return this.supportsBatchUpdates; 573 } 574 575 public void setSupportsBatchUpdates(boolean flag) { 576 this.supportsBatchUpdates = flag; 577 } 578 579 582 public boolean supportsGeneratedKeys() { 583 return supportsGeneratedKeys; 584 } 585 586 589 public void setSupportsGeneratedKeys(boolean flag) { 590 this.supportsGeneratedKeys = flag; 591 } 592 593 598 public boolean shouldRunBatchQuery( 599 DataNode node, 600 Connection con, 601 BatchQuery query, 602 OperationObserver delegate) throws SQLException , Exception { 603 return true; 604 } 605 } | Popular Tags |