1 2 12 package com.versant.core.jdbc; 13 14 import com.versant.core.common.Debug; 15 import com.versant.core.metadata.*; 16 import com.versant.core.metadata.parser.*; 17 import com.versant.core.jdbc.metadata.*; 18 import com.versant.core.jdbc.sql.AutoIncJdbcKeyGenerator; 19 import com.versant.core.jdbc.sql.HighLowJdbcKeyGenerator; 20 import com.versant.core.jdbc.sql.JdbcNameGenerator; 21 import com.versant.core.jdbc.sql.SqlDriver; 22 import com.versant.core.util.BeanUtils; 23 import com.versant.core.util.StringListParser; 24 25 import java.sql.Types ; 26 import java.util.*; 27 28 import com.versant.core.common.BindingSupportImpl; 29 import com.versant.core.common.config.ConfigInfo; 30 31 34 public class JdbcMetaDataBuilder extends MetaDataBuilder 35 implements JdoExtensionKeys { 36 37 private final JdbcConfig jdbcConfig; 38 private final SqlDriver sqlDriver; 39 40 private JdbcNameGenerator nameGenerator; 41 private JdbcMappingResolver mappingResolver; 42 43 public final MetaDataEnums MDE = new MetaDataEnums(); 44 public final JdbcMetaDataEnums jdbcMDE = new JdbcMetaDataEnums(); 45 46 private JdbcKeyGeneratorFactoryRegistry keyGenRegistry; 47 private JdbcConverterFactoryRegistry converterRegistry; 48 private JdbcClassReferenceGraph jdbcClassReferenceGraph; 49 50 53 private Map classInfoMap = new HashMap(); 54 55 public static final String DATASTORE_PK_FIELDNAME = "<pk>"; 57 public static final String CLASS_ID_FIELDNAME = "<class-id>"; 58 public static final String OPT_LOCK_FIELDNAME = "<opt-lock>"; 59 public static final String OWNER_REF_FIELDNAME = "<owner>"; 60 public static final String SEQUENCE_FIELDNAME = "<sequence>"; 61 public static final String VALUE_FIELDNAME = "<value>"; 62 public static final String KEY_FIELDNAME = "<key>"; 63 64 public static final String KEYGEN_HIGHLOW = "HIGHLOW"; 66 public static final String KEYGEN_AUTOINC = "AUTOINC"; 67 68 73 public static class ClassInfo { 74 75 public ClassMetaData cmd; 76 77 public ArrayList elements; 78 public JdbcKeyGeneratorFactory keyGenFactory; 79 public Object keyGenFactoryArgs; 80 public String pkConstraintName; 81 public JdoExtension optimisticLockingExt; 82 public String pkFkConstraintName; 83 public JdbcConstraint pkFkConstraint; 84 public ArrayList indexExts = new ArrayList(); 85 public ArrayList autoIndexes = new ArrayList(); public JdoExtension inheritance; 87 public JdoExtension classIdExt; 88 public boolean noClassIdCol; 89 private Set createdAfterClient; 90 91 public Set getCreatedAfterClient() { 92 if (createdAfterClient == null) { 93 createdAfterClient = new HashSet(); 94 } 95 return createdAfterClient; 96 } 97 } 98 99 102 public JdbcMetaDataBuilder(ConfigInfo config, JdbcConfig jdbcConfig, 103 ClassLoader loader, SqlDriver sqlDriver, boolean quiet) { 104 super(config, loader, quiet); 105 this.jdbcConfig = jdbcConfig; 106 this.sqlDriver = sqlDriver; 107 } 108 109 protected FetchGroupBuilder createFetchGroupBuilder() { 110 return new JdbcFetchGroupBuilder(jmd); 111 } 112 113 public boolean isCdRefsInDefaultFetchGroup() { 114 return jdbcConfig.oidsInDefaultFetchGroup; 115 } 116 117 public int getCdCacheStrategy() { 118 return jdbcConfig.cacheStrategy; 119 } 120 121 public ModelMetaData buildMetaData(JdoRoot[] roots) { 122 keyGenRegistry = new JdbcKeyGeneratorFactoryRegistry(loader); 123 keyGenRegistry.add(KEYGEN_HIGHLOW, 124 keyGenRegistry.getFactory( 125 HighLowJdbcKeyGenerator.Factory.class.getName())); 126 keyGenRegistry.add(KEYGEN_AUTOINC, 127 keyGenRegistry.getFactory( 128 AutoIncJdbcKeyGenerator.Factory.class.getName())); 129 converterRegistry = new JdbcConverterFactoryRegistry(loader); 130 131 mappingResolver = new JdbcMappingResolver(); 132 mappingResolver.init(sqlDriver, parseTypeMappings(), 133 parseJavaTypeMappings()); 134 mappingResolver.registerStoreTypes(mdutils); 135 136 if (jdbcConfig.jdbcKeyGenerator == null) { 137 jdbcConfig.jdbcKeyGenerator = JdbcMetaDataBuilder.KEYGEN_HIGHLOW; 138 } 139 if (jdbcConfig.jdbcKeyGeneratorProps == null) { 140 141 jdbcConfig.jdbcKeyGeneratorProps = Collections.EMPTY_MAP; 142 143 144 } 145 146 if (jdbcConfig.jdbcNameGenerator != null) { 147 nameGenerator = (JdbcNameGenerator)BeanUtils.newInstance( 148 jdbcConfig.jdbcNameGenerator, loader, JdbcNameGenerator.class); 149 } else { 150 nameGenerator = sqlDriver.createJdbcNameGenerator(); 151 } 152 BeanUtils.setProperties(nameGenerator, jdbcConfig.jdbcNameGeneratorProps); 153 jmd.jdbcMetaData = new JdbcMetaData(jmd, jdbcConfig); 154 155 return super.buildMetaData(roots); 156 } 157 158 protected void doHorizontal(ClassMetaData[] ca) { 159 for (int j = 0; j < ca.length; j++) { 161 ClassMetaData cmd = ca[j]; 162 try { 163 createHorizontalFieldMetaData(cmd, quiet); 164 } catch (RuntimeException e) { 165 cmd.addError(e, quiet); 166 } 167 } 168 } 169 170 protected void doEmbedded(ClassMetaData[] ca) { 171 for (int j = 0; j < ca.length; j++) { 173 ClassMetaData cmd = ca[j]; 174 try { 175 createEmbeddeFieldMetaData(cmd, quiet); 176 } catch (RuntimeException e) { 177 cmd.addError(e, quiet); 178 } 179 } 180 } 181 182 protected void checkForHorizontal(JdoClass jdoCls, ClassMetaData cmd) { 183 if (jdoCls.getInheritance(jdbcMDE.INHERITANCE_ENUM) == JdbcClass.INHERITANCE_HORIZONTAL) { 184 cmd.horizontal = true; 185 } 186 } 187 188 public JdbcConfig getJdbcConfig() { 189 return jdbcConfig; 190 } 191 192 public JdbcNameGenerator getNameGenerator() { 193 return nameGenerator; 194 } 195 196 199 public ClassInfo getClassInfo(ClassMetaData cmd) { 200 return (ClassInfo)classInfoMap.get(cmd); 201 } 202 203 206 private ArrayList getClassElements(ClassMetaData cmd) { 207 return getClassInfo(cmd).elements; 208 } 209 210 protected void preBuildFetchGroupsHook() { 211 ClassMetaData[] classes = jmd.classes; 212 int clen = classes.length; 213 214 if (Debug.DEBUG) { 217 Debug.OUT.println("MDB-JDBC: Creating JdbcClass objects ... "); 218 } 219 for (int i = 0; i < clen; i++) { 220 ClassMetaData cmd = classes[i]; 221 if (cmd.pcSuperMetaData != null) { 222 continue; 223 } 224 try { 225 createJdbcClass(cmd, quiet); 226 } catch (RuntimeException e) { 227 cmd.addError(e, quiet); 228 } 229 } 230 231 if (Debug.DEBUG) { 235 Debug.OUT.println("MDB-JDBC: Creating JdbcTable objects ... "); 236 } 237 for (int i = 0; i < clen; i++) { 238 ClassMetaData cmd = classes[i]; 239 try { 240 processBaseClassTable(cmd); 241 } catch (RuntimeException e) { 242 cmd.addError(e, quiet); 243 } 244 245 } 246 247 if (Debug.DEBUG) { 250 Debug.OUT.println("MDB-JDBC: Finding and naming primary keys ... "); 251 } 252 for (int i = 0; i < clen; i++) { 253 ClassMetaData cmd = classes[i]; 254 if (cmd.pcSuperMetaData != null) continue; 255 try { 256 processPrimaryKey(cmd, quiet); 257 } catch (RuntimeException e) { 258 cmd.addError(e, quiet); 259 } 260 } 261 262 if (Debug.DEBUG) { 264 Debug.OUT.println("MDB-JDBC: Creating descriminator columns ... "); 265 } 266 for (int i = 0; i < clen; i++) { 267 ClassMetaData cmd = classes[i]; 268 if (cmd.pcSuperMetaData != null) { 269 continue; 270 } 271 try { 272 processClassIdCol(cmd, quiet, new HashMap()); 273 } catch (RuntimeException e) { 274 cmd.addError(e, quiet); 275 } 276 } 277 278 for (int j = 0; j < clen; j++) { 280 ClassMetaData cmd = classes[j]; 281 ClassInfo cInfo = getClassInfo(cmd.top); 282 cInfo.getCreatedAfterClient().clear(); 283 JdoElement[] elements = cmd.jdoClass.elements; 284 int n = elements.length; 285 for (int i = 0; i < n; i++) { 286 JdoElement o = elements[i]; 287 if (o instanceof JdoExtension) { 288 JdoExtension e = (JdoExtension)o; 289 if (e.key == PERSIST_AFTER) { 290 if (e.nested == null) continue; 291 for (int k = 0; k < e.nested.length; k++) { 292 JdoExtension jdoExtension = e.nested[k]; 293 if (jdoExtension != null) { 294 cInfo.getCreatedAfterClient().add(jmd.getClassMetaData( 295 jdoExtension.value).top); 296 } 297 } 298 } 299 } 300 } 301 } 302 303 if (Debug.DEBUG) { 305 Debug.OUT.println("MDB-JDBC: Calculating maxPkSimpleColumns ... "); 306 } 307 int maxPkSimpleColumns = 0; 308 for (int i = 0; i < clen; i++) { 309 ClassMetaData cmd = classes[i]; 310 try { 311 if (cmd.horizontal) continue; 312 JdbcClass jdbcClass = ((JdbcClass)cmd.storeClass); 313 int n = jdbcClass.table.pkSimpleColumnCount; 314 if (n > maxPkSimpleColumns) { 315 maxPkSimpleColumns = n; 316 } 317 cmd.datastoreIdentityTypeCode = jdbcClass.table.pk[0].javaTypeCode; 318 cmd.datastoreIdentityType = jdbcClass.table.pk[0].javaType; 319 } catch (RuntimeException e) { 320 cmd.addError(e, quiet); 321 } 322 } 323 ((JdbcMetaData)jmd.jdbcMetaData).maxPkSimpleColumns = maxPkSimpleColumns; 324 325 if (Debug.DEBUG) { 328 Debug.OUT.println("MDB-JDBC: Completing optimistic locking ... "); 329 } 330 for (int i = 0; i < clen; i++) { 331 ClassMetaData cmd = classes[i]; 332 if (cmd.pcSuperMetaData != null) continue; 333 try { 334 completeOptimisticLocking(cmd, quiet); 335 } catch (RuntimeException e) { 336 cmd.addError(e, quiet); 337 } 338 } 339 340 if (Debug.DEBUG) { 343 Debug.OUT.println("MDB-JDBC: Creating REF fields ... "); 344 } 345 for (int i = 0; i < clen; i++) { 346 ClassMetaData cmd = classes[i]; 347 try { 348 processRefAndPolyRefFields(cmd, quiet); 349 } catch (RuntimeException e) { 350 cmd.addError(e, quiet); 351 } 352 } 353 354 if (Debug.DEBUG) { 357 Debug.OUT.println("MDB-JDBC: Creating COLLECTION fields ... "); 358 } 359 for (int i = 0; i < clen; i++) { 360 ClassMetaData cmd = classes[i]; 361 try { 362 if (cmd.horizontal) continue; 363 processCollectionFields(cmd, quiet); 364 } catch (RuntimeException e) { 365 cmd.addError(e, quiet); 366 } 367 } 368 369 if (Debug.DEBUG) { 373 Debug.OUT.println( 374 "MDB-JDBC: Finalizing table column arrays and fake fields ... "); 375 } 376 for (int i = 0; i < clen; i++) { 377 ClassMetaData cmd = classes[i]; 378 if (cmd.pcSuperMetaData != null) continue; 380 try { 381 finalizeFakesAndTableColumns(cmd); 382 } catch (RuntimeException e) { 383 cmd.addError(e, quiet); 384 } 385 } 386 387 jdbcClassReferenceGraph = new JdbcClassReferenceGraph(jmd.classes); 388 jdbcClassReferenceGraph.sort(); 389 390 if (Debug.DEBUG) { 391 Debug.OUT.println("MDB-JDBC: Creating constraints ... "); 392 } 393 for (int i = 0; i < clen; i++) { 394 ClassMetaData cmd = classes[i]; 395 try { 396 doConstraints(cmd); 397 } catch (RuntimeException e) { 398 cmd.addError(e, quiet); 399 } 400 } 401 402 jdbcClassReferenceGraph.releaseMem(); 404 405 if (Debug.DEBUG) { 407 Debug.OUT.println("MDB-JDBC: Finalizing fields arrays ... "); 408 } 409 for (int i = 0; i < clen; i++) { 410 ClassMetaData cmd = classes[i]; 411 FieldMetaData[] fa = cmd.fields; 412 if (fa == null) continue; 413 JdbcField[] a = ((JdbcClass)cmd.storeClass).fields = new JdbcField[fa.length]; 414 for (int j = fa.length - 1; j >= 0; j--) { 415 FieldMetaData fmd = fa[j]; 416 fmd.fieldNo = j; JdbcField jdbcField = (JdbcField)fmd.storeField; 418 a[j] = jdbcField; 419 if (jdbcField != null) jdbcField.initMainTableCols(); 420 } 421 } 422 423 if (Debug.DEBUG) { 425 Debug.OUT.println("MDB-JDBC: Choosing shared columns ... "); 426 } 427 SharedColumnChooser sharedColumnChooser = new SharedColumnChooser(); 428 for (int i = 0; i < clen; i++) { 429 ClassMetaData cmd = classes[i]; 430 if (cmd.pcSuperMetaData != null) continue; 431 if (cmd.horizontal) continue; 432 try { 433 sharedColumnChooser.chooseSharedColumns(cmd); 434 } catch (RuntimeException e) { 435 cmd.addError(e, quiet); 436 } 437 } 438 439 if (Debug.DEBUG) { 441 Debug.OUT.println( 442 "MDB-JDBC: Finalizing for update columns for fields ... "); 443 } 444 for (int i = 0; i < clen; i++) { 445 ClassMetaData cmd = classes[i]; 446 JdbcField[] fields = ((JdbcClass)cmd.storeClass).fields; 447 if (fields == null) continue; 448 for (int j = fields.length - 1; j >= 0; j--) { 449 JdbcField f = fields[j]; 450 if (f != null) f.initMainTableColsForUpdate(); 451 } 452 } 453 454 if (Debug.DEBUG) { 456 Debug.OUT.println( 457 "MDB-JDBC: Copying optimistic locking down heirachies ... "); 458 } 459 for (int i = 0; i < clen; i++) { 460 ClassMetaData cmd = classes[i]; 461 ((JdbcClass)cmd.storeClass).copyOptimisticLockingToSubs(); 462 } 463 464 if (Debug.DEBUG) { 466 Debug.OUT.println("MDB-JDBC: Finalizing table constraints ... "); 467 } 468 for (int i = 0; i < clen; i++) { 469 ClassMetaData cmd = classes[i]; 470 try { 471 finalizeConstraints(cmd); 472 } catch (RuntimeException e) { 473 cmd.addError(e, quiet); 474 } 475 } 476 ArrayList tables = ((JdbcMetaData)jmd.jdbcMetaData).getTables(true); 477 int size = tables.size(); 478 for (int i = 0; i < size; i++) { 479 JdbcTable jdbcTable = (JdbcTable)tables.get(i); 480 jdbcTable.nameConstraints(nameGenerator); 481 } 482 for (int i = 0; i < clen; i++) { 483 ClassMetaData cmd = classes[i]; 484 try { 485 finalizeConstraints(cmd); 486 } catch (RuntimeException e) { 487 cmd.addError(e, quiet); 488 } 489 } 490 491 if (Debug.DEBUG) { 493 Debug.OUT.println("MDB-JDBC: Processing index extensions ... "); 494 } 495 for (int i = 0; i < clen; i++) { 496 ClassMetaData cmd = classes[i]; 497 if (cmd.pcSuperMetaData != null) continue; 498 try { 499 createMainTableIndexes(cmd, quiet); 500 } catch (RuntimeException e) { 501 cmd.addError(e, quiet); 502 } 503 } 504 505 if (Debug.DEBUG) { 507 Debug.OUT.println("MDB-JDBC: Naming link table indexes ..."); 508 } 509 for (int i = 0; i < clen; i++) { 510 ClassMetaData cmd = classes[i]; 511 FieldMetaData[] fields = cmd.fields; 512 if (fields == null) continue; 513 for (int j = 0; j < fields.length; j++) { 514 JdbcField jf = (JdbcField)fields[j].storeField; 515 if (jf != null) { 516 try { 517 jf.nameLinkTableIndexes(nameGenerator); 518 } catch (RuntimeException e) { 519 cmd.addError(e, quiet); 520 } 521 } 522 } 523 } 524 525 if (Debug.DEBUG) { 527 Debug.OUT.println("MDB-JDBC: Creating key generators ... "); 528 } 529 createKeyGenerators(quiet); 530 } 531 532 538 private void createMainTableIndexes(ClassMetaData cmd, boolean quiet) { 539 if (cmd.pcSuperMetaData != null) return; 540 541 ArrayList all = new ArrayList(); 542 collectIndexes(cmd, all, quiet); 543 ArrayList auto = new ArrayList(); 544 collectAutoIndexes(cmd, auto); 545 546 HashSet s = new HashSet(); 549 s.addAll(all); 550 for (Iterator i = auto.iterator(); i.hasNext();) { 551 Object o = i.next(); 552 if (s.contains(o)) { 553 i.remove(); 554 } else { 555 s.add(o); 556 } 557 } 558 all.addAll(auto); 559 560 Map tablesToIndexs = new HashMap(); 561 for (int i = 0; i < all.size(); i++) { 562 JdbcIndex index = (JdbcIndex)all.get(i); 563 JdbcTable table = null; 564 boolean ignore = false; 565 if (index.cols.length > 0) { 566 table = index.cols[0].table; 567 ignore = false; 568 for (int j = 1; j < index.cols.length; j++) { 569 JdbcColumn col = index.cols[j]; 570 if (col.table != table) { 571 System.out.println("\n\n WARNING: This composite index contains colums from " + 572 "2 different tables. Ignoring it"); 573 ignore = true; 574 } 575 } 576 } 577 if (ignore) continue; 578 579 Set indexs = (Set)tablesToIndexs.get(table); 580 if (indexs == null) { 581 indexs = new HashSet(); 582 tablesToIndexs.put(table, indexs); 583 } 584 indexs.add(index); 585 } 586 587 for (Iterator iterator = tablesToIndexs.entrySet().iterator(); 588 iterator.hasNext();) { 589 Map.Entry mapEntry = (Map.Entry)iterator.next(); 590 JdbcTable table = (JdbcTable)mapEntry.getKey(); 591 if (table != null) { 592 Set indexs = (Set)mapEntry.getValue(); 593 JdbcIndex[] a = new JdbcIndex[indexs.size()]; 594 indexs.toArray(a); 595 table.indexes = a; 596 for (int i = 0; i < a.length; i++) { 597 if (a[i] != null && a[i].name == null) { 598 generateNameForIndex(nameGenerator, table.name, 599 a[i]); 600 } 601 } 602 } 603 } 604 } 605 606 protected void postAllFieldsCreatedHook() { 607 ClassMetaData[] ca = jmd.classes; 608 609 for (int i = ca.length - 1; i >= 0; i--) { 611 ClassMetaData cmd = ca[i]; 612 JdbcClass jc = (JdbcClass)cmd.storeClass; 613 if (jc == null || jc.fields == null) continue; 614 for (int j = jc.fields.length - 1; j >= 0; j--) { 615 JdbcField f = jc.fields[j]; 616 if (f == null) { 617 continue; 618 } 619 f.stateFieldNo = f.fmd.fieldNo + cmd.superFieldCount; 620 } 621 } 622 623 for (int i = ca.length - 1; i >= 0; i--) { 625 ClassMetaData cmd = ca[i]; 626 JdbcClass jc = (JdbcClass)cmd.storeClass; 627 if (jc == null) continue; 628 jc.buildStateFields(); 629 } 630 fillFGMetaData(); 631 } 632 633 private void collectIndexes(ClassMetaData cmd, ArrayList indexes, 634 boolean quiet) { 635 ArrayList indexExts = getClassInfo(cmd).indexExts; 636 for (int j = 0; j < indexExts.size(); j++) { 637 try { 638 indexes.add(processIndexExtension(cmd, 639 (JdoExtension)indexExts.get(j), quiet)); 640 } catch (RuntimeException e) { 641 cmd.addError(e, quiet); 642 } 643 } 644 ClassMetaData[] subs = cmd.pcSubclasses; 645 if (subs != null) { 646 for (int i = 0; i < subs.length; i++) { 647 try { 648 collectIndexes(subs[i], indexes, quiet); 649 } catch (RuntimeException e) { 650 cmd.addError(e, quiet); 651 } 652 } 653 } 654 } 655 656 private void collectAutoIndexes(ClassMetaData cmd, ArrayList indexes) { 657 indexes.addAll(getClassInfo(cmd).autoIndexes); 658 ClassMetaData[] subs = cmd.pcSubclasses; 659 if (subs != null) { 660 for (int i = 0; i < subs.length; i++) { 661 collectAutoIndexes(subs[i], indexes); 662 } 663 } 664 } 665 666 670 public static void generateNameForIndex(JdbcNameGenerator namegen, String tableName, 671 JdbcIndex idx) { 672 int n = idx.cols.length; 673 String [] cn = new String [n]; 674 for (int i = 0; i < n; i++) cn[i] = idx.cols[i].name; 675 idx.name = namegen.generateIndexName(tableName, cn); 676 } 677 678 681 private ArrayList parseTypeMappings() { 682 String sdb = sqlDriver.getName(); 683 ArrayList in = jdbcConfig.typeMappings; 684 int n = in.size(); 685 ArrayList a = new ArrayList(n); 686 StringListParser p = new StringListParser(); 687 for (int i = 0; i < n; i++) { 688 String s = (String )in.get(i); 689 p.setString(s); 690 JdbcTypeMapping m = new JdbcTypeMapping(); 691 m.parse(p, converterRegistry); 692 String mdb = m.getDatabase(); 693 if (mdb == null || mdb.equals(sdb)) a.add(m); 694 } 695 return a; 696 } 697 698 702 private ArrayList parseJavaTypeMappings() { 703 String sdb = sqlDriver.getName(); 704 ArrayList in = jdbcConfig.javaTypeMappings; 705 int n = in.size(); 706 ArrayList a = new ArrayList(n); 707 StringListParser p = new StringListParser(); 708 for (int i = 0; i < n; i++) { 709 String s = (String )in.get(i); 710 p.setString(s); 711 JdbcJavaTypeMapping m = new JdbcJavaTypeMapping(); 712 m.parse(p, converterRegistry); 713 String mdb = m.getDatabase(); 714 if (mdb == null || mdb.equals(sdb)) a.add(m); 715 } 716 return a; 717 } 718 719 724 private JdbcIndex processIndexExtension(ClassMetaData cmd, JdoExtension e, 725 boolean quiet) { 726 JdbcIndex idx = new JdbcIndex(); 727 idx.name = e.value; 728 ArrayList cols = new ArrayList(); 729 JdoExtension[] a = e.nested; 730 int n = a == null ? 0 : a.length; 731 for (int i = 0; i < n; i++) { 732 JdoExtension ne = a[i]; 733 switch (ne.key) { 734 case JDBC_CLUSTERED: 735 try { 736 idx.clustered = ne.getBoolean(); 737 } catch (RuntimeException x) { 738 cmd.addError(x, quiet); 739 } 740 break; 741 case JDBC_UNIQUE: 742 try { 743 idx.unique = ne.getBoolean(); 744 } catch (RuntimeException x) { 745 cmd.addError(x, quiet); 746 } 747 break; 748 case FIELD_NAME: 749 JdbcColumn[] mtc; 750 String fname = ne.getString(); 751 if (fname.equals(DATASTORE_PK_FIELDNAME)) { 752 mtc = ((JdbcClass)cmd.storeClass).table.pk; 753 } else { 754 FieldMetaData fmd = cmd.getFieldMetaData(fname); 755 if (fmd == null) { 756 RuntimeException x = BindingSupportImpl.getInstance().runtime("Field '" + ne.value + 757 "' not found\n" + ne.getContext()); 758 cmd.addError(x, quiet); 759 } 760 JdbcField jf = (JdbcField)fmd.storeField; 761 if (jf == null || jf.mainTableCols == null) { 762 RuntimeException x = BindingSupportImpl.getInstance().runtime( 763 "Field '" + ne.value + 764 "' is not stored in the main table\n" + ne.getContext()); 765 fmd.addError(x, quiet); 766 } 767 mtc = jf.mainTableCols; 768 } 769 for (int j = 0; j < mtc.length; j++) cols.add(mtc[j]); 770 break; 771 default: 772 MetaDataBuilder.throwUnexpectedExtension(ne); 773 } 774 } 775 n = cols.size(); 776 if (n == 0) { 777 RuntimeException x = BindingSupportImpl.getInstance().runtime( 778 "Index does not include any fields\n" + e.getContext()); 779 cmd.addError(x, quiet); 780 return null; 781 } 782 JdbcColumn[] idxCols = new JdbcColumn[n]; 783 cols.toArray(idxCols); 784 idx.setCols(idxCols); 785 if (idx.name != null) { 786 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 787 try { 788 nameGenerator.addIndexName( 789 jdbcClass.table.name, 790 idx.name); 791 } catch (IllegalArgumentException x) { 792 RuntimeException ex = BindingSupportImpl.getInstance().runtime( 793 x.getMessage(), x); 794 cmd.addError(ex, quiet); 795 } 796 } 797 return idx; 798 } 799 800 private void fillFGMetaData() { 801 ClassMetaData[] classes = jmd.classes; 802 int clen = classes.length; 803 if (Debug.DEBUG) { 804 Debug.OUT.println("MDB-JDBC: Filling fetch group meta data ... "); 805 } 806 for (int i = 0; i < clen; i++) { 807 ClassMetaData cmd = classes[i]; 808 processFetchGroups(cmd); 809 } 810 } 811 812 815 private void completeOptimisticLocking(ClassMetaData cmd, boolean quiet) { 816 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 817 ClassInfo info = getClassInfo(cmd); 818 switch (jdbcClass.optimisticLocking) { 819 case JdbcClass.OPTIMISTIC_LOCKING_VERSION: 820 case JdbcClass.OPTIMISTIC_LOCKING_TIMESTAMP: 821 processTimestampOrRowVersionLocking(jdbcClass, cmd, 822 info.optimisticLockingExt, info.elements, quiet); 823 break; 824 } 825 } 826 827 private void processTimestampOrRowVersionLocking(JdbcClass jdbcClass, 828 ClassMetaData cmd, JdoExtension e, ArrayList jdbcElements, 829 boolean quiet) { 830 boolean timestamp = 831 jdbcClass.optimisticLocking == JdbcClass.OPTIMISTIC_LOCKING_TIMESTAMP; 832 JdoExtension[] nested = e == null ? null : e.nested; 833 if (nested != null && nested[0].key == JdoExtensionKeys.FIELD_NAME) { 834 if (nested.length > 1) { 835 RuntimeException x = BindingSupportImpl.getInstance().runtime("Unexpected extension: " + 836 nested[1].getContext()); 837 cmd.addError(x, quiet); 838 } 839 String fieldName = nested[0].value; 840 FieldMetaData fmd = cmd.getFieldMetaData(fieldName); 841 if (fmd == null) { 842 RuntimeException x = BindingSupportImpl.getInstance().runtime("Field '" + fieldName + 843 " not found\n" + nested[0].getContext()); 844 cmd.addError(x, quiet); 845 } 846 int tc = fmd.typeCode; 847 if (timestamp) { 848 if (tc != MDStatics.DATE) { 849 RuntimeException x = BindingSupportImpl.getInstance().runtime( 850 "Field '" + fieldName + 851 " is not a java.util.Date\n" + nested[0].getContext()); 852 fmd.addError(x, quiet); 853 } 854 } else { 855 if (tc != MDStatics.INT && tc != MDStatics.SHORT 856 && tc != MDStatics.BYTE) { 857 RuntimeException x = BindingSupportImpl.getInstance().runtime( 858 "Field '" + fieldName + 859 " is not an int, short or byte\n" + nested[0].getContext()); 860 fmd.addError(x, quiet); 861 } 862 } 863 cmd.optimisticLockingField = fmd; 864 jdbcClass.optimisticLockingField = (JdbcSimpleField)fmd.storeField; 865 fmd.setAutoSet(MDStatics.AUTOSET_BOTH); 866 } else { 867 JdbcColumn tc = createColumn(nested, 868 OPT_LOCK_FIELDNAME, timestamp ? (Class )Date.class : (Class )Short.TYPE); 869 JdbcSimpleField f = jdbcClass.optimisticLockingField = new JdbcSimpleField(); 871 f.fake = true; 872 f.col = tc; 873 FieldMetaData fmd = f.fmd = new FieldMetaData(); 874 fmd.fake = true; 875 fmd.category = MDStatics.CATEGORY_SIMPLE; 876 fmd.primaryField = true; 877 fmd.classMetaData = cmd; 878 fmd.defaultFetchGroup = true; 879 fmd.storeField = f; 880 881 fmd.name = timestamp ? "jdoTimestamp" : "jdoVersion"; 882 883 884 fmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT; 885 fmd.setType(tc.javaType); 886 fmd.setAutoSet(MDStatics.AUTOSET_BOTH); 887 jdbcElements.add(f); 888 cmd.optimisticLockingField = fmd; 889 } 890 } 891 892 895 private void processFetchGroups(ClassMetaData cmd) { 896 FetchGroup[] groups = cmd.fetchGroups; 897 int groupsLen = groups == null ? 0 : groups.length; 898 for (int i = 0; i < groupsLen; i++) { 899 FetchGroup g = groups[i]; 900 int totCols = 0; 901 FetchGroupField[] fields = g.fields; 902 if (fields == null) { 903 continue; 904 } 905 int fieldsLen = fields.length; 906 for (int j = 0; j < fieldsLen; j++) { 907 FetchGroupField field = fields[j]; 908 FieldMetaData fmd = field.fmd; 909 JdbcField jdbcField = (JdbcField)fmd.storeField; 910 JdoExtension ext = field.extension; 911 if (ext != null && ext.nested != null) { 912 JdoExtension[] nested = ext.nested; 913 int nestedLen = nested.length; 914 for (int k = 0; k < nestedLen; k++) { 915 JdoExtension e = nested[k]; 916 switch (e.key) { 917 case JDBC_USE_JOIN: 918 try { 919 field.jdbcUseJoin = e.getEnum( 920 jdbcMDE.USE_JOIN_ENUM); 921 } catch (RuntimeException x) { 922 cmd.addError(x, quiet); 923 } 924 break; 925 case JDBC_USE_KEY_JOIN: 926 if (fmd.category != MDStatics.CATEGORY_MAP) { 927 RuntimeException x = BindingSupportImpl.getInstance().runtime("The jdbc-use-key-join option is only " + 928 "valid for Map fields\n" + 929 e.getContext()); 930 cmd.addError(x, quiet); 931 } 932 try { 933 field.jdbcUseKeyJoin = e.getEnum( 934 jdbcMDE.USE_JOIN_ENUM); 935 } catch (RuntimeException x) { 936 cmd.addError(x, quiet); 937 } 938 break; 939 default: 940 if (e.isJdbc()) { 941 MetaDataBuilder.throwUnexpectedExtension(e); 942 } 943 } 944 } 945 } 946 if (jdbcField == null) continue; 947 if (field.jdbcUseJoin == 0) { 948 if (field.nextFetchGroup != null) { 949 field.jdbcUseJoin = jdbcField.useJoin; 950 } else { 951 field.jdbcUseJoin = JdbcField.USE_JOIN_NO; 952 } 953 } 954 if (field.jdbcUseKeyJoin == 0) { 955 if (field.nextKeyFetchGroup != null) { 956 field.jdbcUseKeyJoin = jdbcField.getUseKeyJoin(); 957 } else { 958 field.jdbcUseKeyJoin = JdbcField.USE_JOIN_NO; 959 } 960 } 961 if (jdbcField.mainTableCols != null) { 962 totCols += jdbcField.mainTableCols.length; 963 } 964 } 965 g.jdbcTotalCols = totCols; 966 } 967 } 968 969 972 private void processRefAndPolyRefFields(ClassMetaData cmd, boolean quiet) { 973 ArrayList elements = getClassElements(cmd); 974 int nelements = elements.size(); 975 for (int i = 0; i < nelements; i++) { 976 Object o = elements.get(i); 977 if (o instanceof JdbcRefField) { 978 processRefField((JdbcRefField)o, quiet); 979 } else if (o instanceof JdbcPolyRefField) { 980 JdbcPolyRefField f = (JdbcPolyRefField)o; 981 f.processMetaData(f.fmd.jdoField, this); 982 } 983 } 984 } 985 986 private void doConstraints(ClassMetaData cmd) { 987 for (int i = 0; i < cmd.fields.length; i++) { 988 FieldMetaData fmd = cmd.fields[i]; 989 if (fmd.storeField instanceof JdbcRefField) { 990 createConstraint((JdbcRefField) fmd.storeField); 991 } 992 } 993 } 994 995 998 private void processCollectionFields(ClassMetaData cmd, boolean quiet) { 999 if (cmd.horizontal) return; 1000 ArrayList elements = getClassElements(cmd); 1001 int nelements = elements.size(); 1002 for (int i = 0; i < nelements; i++) { 1003 Object o = elements.get(i); 1004 if (o instanceof JdbcCollectionField) { 1005 processCollectionField((JdbcCollectionField)o, quiet); 1006 } 1007 } 1008 } 1009 1010 1013 private void processRefField(JdbcRefField f, boolean quiet) { 1014 FieldMetaData fmd = f.fmd; 1015 f.targetClass = fmd.typeMetaData; 1016 JdbcClass target = (JdbcClass)f.targetClass.storeClass; 1017 JdoField jdoField = fmd.jdoField; 1018 JdoElement context = jdoField == null 1019 ? (JdoElement)fmd.typeMetaData.jdoClass 1020 : (JdoElement)jdoField; 1021 processRefFieldImpl(target, f, fmd, context, 1022 jdoField == null ? null : jdoField.extensions, quiet); 1023 1024 } 1025 1026 public void processRefFieldImpl(JdbcClass target, JdbcRefField f, 1027 FieldMetaData fmd, JdoElement context, JdoExtension[] extensions, 1028 boolean quiet) { 1029 if (target != null) { 1030 f.useJoin = target.useJoin; 1031 } else { 1032 f.useJoin = JdbcRefField.USE_JOIN_NO; 1033 } 1034 if (f.useJoin == JdbcRefField.USE_JOIN_NO && fmd.isDefaultFetchGroupTrue()) { 1035 f.useJoin = JdbcRefField.USE_JOIN_OUTER; 1036 } 1037 1038 JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder( 1039 fmd.classMetaData, this, 1040 f.targetClass, context, fmd.name, 1041 extensions, quiet); 1042 1043 f.cols = rdb.getCols(); 1044 if (rdb.getUseJoin() != 0) f.useJoin = rdb.getUseJoin(); 1045 1046 for (int i = 0; i < f.cols.length; i++) { 1047 f.cols[i].comment = fmd.getCommentName(); 1048 } 1049 1050 boolean nulls = fmd.nullValue != MDStatics.NULL_VALUE_EXCEPTION; 1051 int nc = f.cols.length; 1052 for (int i = 0; i < nc; i++) f.cols[i].nulls = nulls; 1053 1054 f.includeForChangedLocking = true; 1057 for (int i = 0; i < nc; i++) { 1058 if (!f.cols[i].equalityTest) { 1059 f.includeForChangedLocking = false; 1060 break; 1061 } 1062 } 1063 f.constraintName = rdb.getConstraintName(); 1064 f.createConstraint = !rdb.isDoNotCreateConstraint(); 1065 } 1066 1067 private boolean isCircularRef(ClassMetaData cmd1, ClassMetaData cmd2) { 1068 return jdbcClassReferenceGraph.isCircularRef(cmd1, cmd2); 1069 } 1070 1071 private void createConstraint(JdbcRefField f) { 1072 final JdbcClass jdbcClass = (JdbcClass)f.fmd.classMetaData.storeClass; 1073 boolean createConstraint = f.createConstraint && f.targetClass != null 1074 && (!(f.fmd.nullValue != MDStatics.NULL_VALUE_EXCEPTION) 1075 || sqlDriver.isNullForeignKeyOk()); 1076 1077 1078 1082 if (createConstraint && isCircularRef(jdbcClass.cmd, f.fmd.typeMetaData)) { 1083 if (!getClassInfo(jdbcClass.cmd.top).getCreatedAfterClient().contains( 1084 f.fmd.typeMetaData.top)) { 1085 createConstraint = false; 1086 } 1087 } 1088 1089 if (createConstraint && jdbcClass.cmd.top == f.fmd.typeMetaData.top) { 1090 createConstraint = false; 1091 } 1092 1093 if (createConstraint) { 1095 JdbcConstraint c = new JdbcConstraint(); 1096 c.name = f.constraintName; 1097 c.src = jdbcClass.table; 1098 c.srcCols = f.cols; 1099 c.dest = ((JdbcClass)f.targetClass.storeClass).table; 1100 f.constraint = c; 1101 if (c.name != null) { 1102 nameGenerator.addRefConstraintName(c.src.name, 1103 c.name); 1104 } 1105 } 1106 } 1107 1108 1111 public JdbcColumn findColumn(List cols, JdbcSimpleField refField) { 1112 for (int i = cols.size() - 1; i >= 0; i--) { 1113 JdbcColumn col = (JdbcColumn)cols.get(i); 1114 if (col.refField == refField) return col; 1115 } 1116 return null; 1117 } 1118 1119 1122 private void processCollectionField(JdbcCollectionField f, boolean quiet) { 1123 FieldMetaData fmd = f.fmd; 1124 JdoField jdoField = fmd.jdoField; 1125 JdoElement context; 1126 if (jdoField == null) { 1127 if (fmd.typeMetaData == null) { 1128 context = fmd.classMetaData.jdoClass; 1129 } else { 1130 context = fmd.typeMetaData.jdoClass; 1131 } 1132 } else { 1133 context = jdoField; 1134 } 1135 try { 1136 f.processMetaData(context, this, quiet); 1137 } catch (RuntimeException e) { 1138 fmd.addError(e, quiet); 1139 } 1140 } 1141 1142 1147 private void createKeyGenerators(boolean quite) { 1148 HashSet keygenSet = new HashSet(); 1149 HashSet keygenTables = new HashSet(17); 1150 ClassMetaData[] classes = jmd.classes; 1151 int clen = classes.length; 1152 for (int i = 0; i < clen; i++) { 1153 ClassMetaData cmd = classes[i]; 1154 if (cmd.horizontal) continue; 1155 if (cmd.pcSuperMetaData != null) continue; 1156 ClassInfo info = getClassInfo(cmd); 1157 JdbcKeyGeneratorFactory f = info.keyGenFactory; 1158 if (f == null) continue; 1159 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1160 JdbcKeyGenerator keygen; 1161 try { 1162 keygen = f.createJdbcKeyGenerator(cmd.qname, jdbcClass.table, 1163 info.keyGenFactoryArgs); 1164 } catch (RuntimeException e) { 1165 cmd.addError(BindingSupportImpl.getInstance().runtime(e.getMessage() + "\n" + 1166 cmd.jdoClass.getContext(), e), quite); 1167 continue; 1168 } 1169 1170 jdbcClass.setJdbcKeyGenerator(keygen); 1172 1173 if (keygenSet.contains(keygen)) continue; 1174 keygenSet.add(keygen); 1175 keygen.addKeyGenTables(keygenTables, this); 1176 1177 if (keygen.isPostInsertGenerator()) { 1179 jdbcClass.table.pk[0].autoinc = true; 1180 sqlDriver.updateClassForPostInsertKeyGen(cmd, mappingResolver); 1183 } 1184 } 1185 JdbcMetaData jdbcMetaData = (JdbcMetaData)jmd.jdbcMetaData; 1186 jdbcMetaData.keyGenTables = new JdbcTable[keygenTables.size()]; 1187 keygenTables.toArray(jdbcMetaData.keyGenTables); 1188 } 1189 1190 1196 private void finalizeFakesAndTableColumns(ClassMetaData cmd) { 1197 ArrayList elements = getClassElements(cmd); 1198 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1199 if (elements != null) { 1200 collectSubclassElements(cmd, elements); 1201 1202 JdbcNameGenerator nameGen = nameGenerator; 1203 String tableName = jdbcClass.tableName; 1204 1205 JdbcColumn classIdCol = jdbcClass.classIdCol; 1207 if (classIdCol != null) { 1208 if (classIdCol.name == null) { 1209 classIdCol.name = nameGen.generateClassIdColumnName( 1210 tableName); 1211 } else { 1212 nameGen.addColumnName(tableName, classIdCol.name); 1213 } 1214 } 1215 1216 ArrayList cols = new ArrayList(elements.size()); 1219 ArrayList fakes = new ArrayList(); 1220 JdbcTable table = jdbcClass.table; 1221 for (int i = 0; i < elements.size(); i++) { 1222 Object o = elements.get(i); 1223 if (o instanceof JdbcField) { 1224 JdbcField f = (JdbcField)o; 1225 f.setMainTable(table); 1226 if (!f.fmd.primaryKey) f.nameColumns(tableName, nameGen); 1227 int pos = cols.size(); 1228 f.addMainTableCols(cols); 1229 if (f.fmd.classMetaData.pcSuperMetaData!= null) { 1231 int pos2 = cols.size(); 1232 for (int j = pos; j < pos2; j++) { 1233 JdbcColumn sc = (JdbcColumn)cols.get(j); 1234 sc.nulls = true; 1235 } 1236 } 1237 if (f.fake) { 1238 fakes.add(f); 1239 } 1240 } else { JdbcColumn c = (JdbcColumn)o; 1242 c.setTable(table); 1243 cols.add(c); 1244 } 1245 } 1246 1247 doNullIndicatorColumn(cmd, elements); 1249 1250 int numFakes = fakes.size(); 1252 if (numFakes > 0 && cmd.fields != null) { 1253 int n = cmd.fields.length; 1254 FieldMetaData[] a = new FieldMetaData[n + numFakes]; 1255 System.arraycopy(cmd.fields, 0, a, 0, n); 1256 for (int i = 0; i < numFakes; i++, n++) { 1257 JdbcField jdbcField = (JdbcField)fakes.get(i); 1258 a[n] = jdbcField.fmd; 1259 } 1260 cmd.fields = a; 1261 } 1262 1263 int nc = cols.size(); 1265 JdbcColumn[] a = new JdbcColumn[nc]; 1266 cols.toArray(a); 1267 for (int i = 0; i < nc; i++) { 1268 JdbcColumn c = a[i]; 1269 if (c.name == null) { 1270 throw BindingSupportImpl.getInstance().internal("Column has no name: " + c + "\n" + 1271 cmd.jdoClass.getContext()); 1272 } 1273 if (c.jdbcType == Types.NULL) { 1274 throw BindingSupportImpl.getInstance().internal("Column has NULL jdbcType: " + c + "\n" + 1275 cmd.jdoClass.getContext()); 1276 } 1277 if (c.table == null) { 1278 throw BindingSupportImpl.getInstance().internal("Column null table: " + c + "\n" + 1279 cmd.jdoClass.getContext()); 1280 } 1281 if (!sqlDriver.isBatchingSupportedForJdbcType(c.jdbcType)) { 1282 jdbcClass.noBatching = true; 1283 } 1284 } 1285 1286 jdbcClass.table.cols = a; 1288 } 1289 1290 ClassMetaData[] subclasses = cmd.pcSubclasses; 1292 if (subclasses == null) return; 1293 for (int i = 0; i < subclasses.length; i++) { 1294 ((JdbcClass)subclasses[i].storeClass).setClassIdCol(jdbcClass.classIdCol); 1295 finalizeFakesAndTableColumns(subclasses[i]); 1296 } 1297 } 1298 1299 1303 private void doNullIndicatorColumn(ClassMetaData cmd, ArrayList elements) { 1304 if (true) return; 1306 FieldMetaData[] fmds = cmd.fields; 1308 for (int i = 0; i < fmds.length; i++) { 1309 FieldMetaData fmd = fmds[i]; 1310 if (fmd.isEmbeddedRef()) { 1311 if (fmd.jdoField != null && fmd.jdoField.extensions != null) { 1312 JdoExtension ext = JdoExtension.find(JdoExtensionKeys.NULL_INDICATOR, fmd.jdoField.extensions); 1313 if (ext != null) { 1314 boolean extFound = false; 1315 if (ext.nested != null) { 1317 JdoExtension colNameExt = ext.nested[0]; 1318 if (colNameExt.key == JdoExtensionKeys.JDBC_COLUMN_NAME) { 1319 extFound = true; 1320 boolean createColumn = true; 1322 for (int l = 0; l < elements.size(); l++) { 1323 Object o1 = elements.get(l); 1324 if (o1 instanceof JdbcSimpleField) { 1325 JdbcSimpleField sf = (JdbcSimpleField) o1; 1326 if (sf.col.name == ext.value) { 1327 createColumn = false; 1328 } 1329 } 1330 } 1331 if (createColumn) { 1332 JdbcColumn col = createColumn(ext.nested, 1333 CLASS_ID_FIELDNAME, Integer.TYPE); 1334 JdbcSimpleField f = new JdbcSimpleField(); 1335 f.fake = true; 1336 f.col = col; 1337 FieldMetaData nullFmd = f.fmd = new FieldMetaData(); 1338 nullFmd.fake = true; 1339 nullFmd.category = MDStatics.CATEGORY_SIMPLE; 1340 nullFmd.classMetaData = cmd; 1341 nullFmd.defaultFetchGroup = true; 1342 nullFmd.storeField = f; 1343 nullFmd.name = fmd.name + "_null_indicator"; 1344 nullFmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT; 1345 nullFmd.setType(col.javaType); 1346 fmd.setNullIndicatorFmd(nullFmd); 1347 elements.add(f); 1348 } 1349 } 1350 } 1351 if (!extFound) { 1352 throw BindingSupportImpl.getInstance().unsupported( 1353 "Found a '" 1354 + JdoExtension.toKeyString(JdoExtensionKeys.NULL_INDICATOR) 1355 + "' extension with no '" 1356 + JdoExtension.toKeyString(JdoExtensionKeys.JDBC_COLUMN_NAME) 1357 + "' nested extension"); 1358 } 1359 } 1360 } 1361 } 1362 } 1363 } 1364 1365 1369 private void finalizeConstraints(ClassMetaData cmd) { 1370 ClassInfo info = getClassInfo(cmd); 1371 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1372 JdbcField[] fields = jdbcClass.fields; 1373 int len = fields.length; 1374 ArrayList cons = new ArrayList(); 1375 JdbcConstraint pkFkConstraint = info.pkFkConstraint; 1376 if (pkFkConstraint != null) { 1377 if (pkFkConstraint.name == null) { 1378 pkFkConstraint.generateName(nameGenerator); 1379 } 1380 cons.add(pkFkConstraint); 1381 } 1382 JdbcTable table = jdbcClass.table; 1383 for (int i = 0; i < len; i++) { 1384 JdbcField field = fields[i]; 1385 if (field != null && field.mainTable == jdbcClass.table) { 1386 field.addConstraints(cons); 1387 } 1388 } 1389 int n = cons.size(); 1390 if (n > 0) { 1391 table.addConstraints(cons); 1392 } 1393 } 1394 1395 1400 private void collectSubclassElements(ClassMetaData cmd, ArrayList elements) { 1401 ClassMetaData[] subclasses = cmd.pcSubclasses; 1402 if (subclasses == null) return; 1403 for (int i = 0; i < subclasses.length; i++) { 1404 ClassMetaData sc = subclasses[i]; 1405 if (((JdbcClass)sc.storeClass).table == ((JdbcClass)cmd.storeClass).table) { 1406 ClassInfo scInfo = getClassInfo(sc); 1407 elements.addAll(scInfo.elements); 1408 scInfo.elements = null; 1409 collectSubclassElements(sc, elements); 1410 } 1411 } 1412 } 1413 1414 1420 private void processPrimaryKey(ClassMetaData cmd, boolean quiet) { 1421 if (cmd.identityType == MDStatics.IDENTITY_TYPE_APPLICATION) { 1423 processPrimaryKeyAppIdentity(cmd, quiet); 1424 } else { 1425 processPrimaryKeyDatastoreIdentity(cmd); 1426 } 1427 1428 ClassInfo info = getClassInfo(cmd); 1430 ClassMetaData pccmd = cmd.pcSuperMetaData; 1431 if (pccmd != null 1432 && ((JdbcClass)cmd.storeClass).table != ((JdbcClass)pccmd.storeClass).table) { 1433 JdbcConstraint c = new JdbcConstraint(); 1434 c.name = info.pkFkConstraintName; 1435 c.src = ((JdbcClass)cmd.storeClass).table; 1436 c.srcCols = ((JdbcClass)cmd.storeClass).table.pk; 1437 c.dest = ((JdbcClass)pccmd.storeClass).table; 1438 if (c.name != null) { 1439 nameGenerator.addRefConstraintName( 1440 c.src.name, c.name); 1441 } 1442 info.pkFkConstraint = c; 1443 } 1444 1445 if (cmd.pcSubclasses == null) return; 1446 for (int j = 0; j < cmd.pcSubclasses.length; j++) { 1447 processPrimaryKey(cmd.pcSubclasses[j], quiet); 1448 } 1449 } 1450 1451 1456 private void processPrimaryKeyDatastoreIdentity(ClassMetaData cmd) { 1457 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1458 JdbcTable table = jdbcClass.table; 1459 JdbcColumn pkcol = null; 1460 1461 ArrayList jdbcElements = getClassElements(cmd); 1462 int elen = jdbcElements.size(); 1463 for (int i = 0; i < elen; i++) { 1464 Object o = jdbcElements.get(i); 1465 if (!(o instanceof JdbcColumn)) continue; 1466 JdbcColumn c = (JdbcColumn)o; 1467 if (c.pk) { 1468 if (pkcol != null) { 1469 throw BindingSupportImpl.getInstance().runtime("Class " + cmd.qname + 1470 " has multiple jdbc-primary-key extensions\n" + 1471 cmd.jdoClass.getContext()); 1472 } 1473 pkcol = c; 1474 } 1475 } 1476 if (cmd.pcSuperMetaData != null) { 1477 if (pkcol != null) { 1478 throw BindingSupportImpl.getInstance().runtime("Class " + cmd.qname + " has a " + 1479 "persistence-capable-superclass so use the inheritance " + 1480 "extension to specify its primary-key\n" + 1481 cmd.jdoClass.getContext()); 1482 } 1483 if (table != ((JdbcClass)cmd.pcSuperMetaData.storeClass).table) { 1486 createVerticalInheritancePK(cmd); 1487 } 1488 } else { 1489 if (pkcol == null) { 1490 pkcol = createColumn(null, 1491 DATASTORE_PK_FIELDNAME, Integer.TYPE); 1492 jdbcElements.add(0, pkcol); 1493 } 1494 if (pkcol.name != null) { 1496 try { 1497 nameGenerator.addColumnName(table.name, pkcol.name); 1498 } catch (IllegalArgumentException e) { 1499 throw BindingSupportImpl.getInstance().runtime("Invalid jdbc-column-name for datastore identity primary key: " + 1500 e.getMessage() + "\n" + cmd.jdoClass.getContext()); 1501 } 1502 } else { 1503 pkcol.name = nameGenerator.generateDatastorePKName( 1504 table.name); 1505 } 1506 table.setPk(new JdbcColumn[]{pkcol}); 1507 } 1508 } 1509 1510 1515 private void createVerticalInheritancePK(ClassMetaData cmd) { 1516 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1517 JdbcTable table = jdbcClass.table; 1518 JdbcTable superTable = ((JdbcClass)cmd.pcSuperMetaData.storeClass).table; 1519 JdoExtension inheritance = getClassInfo(cmd).inheritance; 1520 JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(cmd, this, 1521 cmd.pcSuperMetaData, inheritance, null, 1522 inheritance == null ? null : inheritance.nested, quiet); 1523 JdbcColumn[] a = rdb.getCols(); 1524 for (int i = 0; i < a.length; i++) { 1525 if (a[i].name == null) a[i].name = superTable.pk[i].name; 1526 a[i].pk = true; 1527 } 1528 table.setPk(a); 1529 ArrayList jdbcElements = getClassElements(cmd); 1530 for (int i = 0; i < a.length; i++) { 1531 try { 1532 a[i].addColumnNames(table.name, nameGenerator); 1533 } catch (IllegalArgumentException e) { 1534 throw BindingSupportImpl.getInstance().runtime("Invalid jdbc-column-name: " + 1535 e.getMessage() + "\n" + inheritance.getContext()); 1536 } 1537 jdbcElements.add(i, a[i]); 1538 } 1539 } 1540 1541 1545 private void processPrimaryKeyAppIdentity(ClassMetaData cmd, boolean quiet) { 1546 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1547 JdbcTable table = jdbcClass.table; 1548 JdbcNameGenerator ng = nameGenerator; 1549 FieldMetaData[] fields = cmd.pkFields; 1550 JdbcColumn[] pkcols = null; 1551 int pkFieldCount = fields == null ? 0 : fields.length; 1552 if (fields != null) { 1553 pkcols = new JdbcColumn[pkFieldCount]; 1554 for (int i = 0; i < pkFieldCount; i++) { 1555 try { 1556 JdbcSimpleField jdbcSimpleField = (JdbcSimpleField)fields[i].storeField; 1557 pkcols[i] = jdbcSimpleField.col; 1558 pkcols[i].refField = jdbcSimpleField; 1559 } catch (ClassCastException e) { 1560 RuntimeException x = BindingSupportImpl.getInstance().runtime("Only simple fields may be mapped as Primary Key's.\n" + 1561 cmd.jdoClass.getContext()); 1562 cmd.addError(x, quiet); 1563 } 1564 } 1565 } 1566 ClassMetaData pccmd = cmd.pcSuperMetaData; 1567 if (pccmd != null && ((JdbcClass)pccmd.storeClass).inheritance != JdbcClass.INHERITANCE_HORIZONTAL) { 1568 if (pkcols != null) { 1569 throw BindingSupportImpl.getInstance().runtime("Class " + cmd.qname + " has a " + 1570 "persistence-capable-superclass so use the inheritance " + 1571 "extension to specify its primary-key\n" + 1572 cmd.jdoClass.getContext()); 1573 } 1574 if (table != ((JdbcClass)pccmd.storeClass).table) { 1577 createVerticalInheritancePK(cmd); 1578 } 1579 } else { 1580 if (pkcols == null) { 1581 RuntimeException e = BindingSupportImpl.getInstance().runtime("Class " + 1582 cmd.qname + " has application identity " + 1583 "but no primary-key fields\n" + 1584 cmd.jdoClass.getContext()); 1585 cmd.addError(e, quiet); 1586 } else { 1587 for (int i = 0; i < pkFieldCount; i++) { 1588 String cn = pkcols[i].name; 1589 if (cn == null) { 1590 pkcols[i].name = ng.generateFieldColumnName(table.name, 1591 fields[i].name, true); 1592 } else { 1593 try { 1594 ng.addColumnName(table.name, cn); 1595 } catch (IllegalArgumentException x) { 1596 throw BindingSupportImpl.getInstance().runtime("Invalid jdbc-column-name: " + x.getMessage() + "\n" + 1597 cmd.jdoClass.getContext()); 1598 } 1599 } 1600 } 1601 table.setPk(pkcols); 1602 } 1603 } 1604 } 1605 1606 1611 private void processBaseClassTable(ClassMetaData cmd) { 1612 ClassMetaData pccmd = cmd.pcSuperMetaData; 1613 if (pccmd != null) return; 1614 createClassTable(cmd); 1615 JdbcClass jdbcClass = ((JdbcClass)cmd.storeClass); 1616 if (cmd.horizontal) { 1617 jdbcClass.doNotCreateTable = true; 1618 } 1619 if (cmd.pcSubclasses == null) return; 1620 for (int j = 0; j < cmd.pcSubclasses.length; j++) { 1621 processSubclassTable(cmd.pcSubclasses[j]); 1622 } 1623 } 1624 1625 private void createClassTable(ClassMetaData cmd) { 1626 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1627 JdbcTable table = new JdbcTable(); 1628 table.sqlDriver = sqlDriver; 1629 table.name = jdbcClass.tableName; 1630 table.comment = cmd.qname; 1631 if (table.name == null) { 1632 table.name = nameGenerator.generateClassTableName(cmd.qname); 1633 } else { 1634 addTableName(table, cmd); 1635 } 1636 jdbcClass.setTable(table); 1637 fillTablePkConstraintName(cmd, table); 1638 } 1639 1640 1644 private void processSubclassTable(ClassMetaData cmd) { 1645 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1646 ClassMetaData pccmd = cmd.pcSuperMetaData; 1647 switch (jdbcClass.inheritance) { 1648 case JdbcClass.INHERITANCE_FLAT: 1649 jdbcClass.setTable(((JdbcClass)pccmd.storeClass).table); 1650 break; 1651 case JdbcClass.INHERITANCE_VERTICAL: 1652 createClassTable(cmd); 1653 break; 1654 default: 1655 throw BindingSupportImpl.getInstance().internal("Unknown inheritance strategy: " + jdbcClass.inheritance + 1656 " for " + cmd.qname); 1657 } 1658 1659 if (cmd.pcSubclasses == null) return; 1660 for (int j = 0; j < cmd.pcSubclasses.length; j++) { 1661 processSubclassTable(cmd.pcSubclasses[j]); 1662 } 1663 } 1664 1665 private void addTableName(JdbcTable table, 1666 ClassMetaData cmd) { 1667 try { 1668 nameGenerator.addTableName(table.name); 1669 } catch (IllegalArgumentException x) { 1670 throw BindingSupportImpl.getInstance().runtime("Invalid jdbc-table-name: " + x.getMessage() + "\n" + 1671 cmd.jdoClass.getContext()); 1672 } 1673 } 1674 1675 private void fillTablePkConstraintName(ClassMetaData cmd, JdbcTable table) { 1676 table.pkConstraintName = getClassInfo(cmd).pkConstraintName; 1677 if (table.pkConstraintName == null) { 1678 table.pkConstraintName = nameGenerator.generatePkConstraintName( 1679 table.name); 1680 } else { 1681 try { 1682 nameGenerator.addPkConstraintName(table.name, table.pkConstraintName); 1683 } catch (IllegalArgumentException e) { 1684 throw BindingSupportImpl.getInstance().runtime("Invalid jdbc-pk-constraint-name: " + 1685 e.getMessage() + "\n" + cmd.jdoClass.getContext(), e); 1686 } 1687 } 1688 } 1689 1690 1695 private void createJdbcClass(ClassMetaData cmd, boolean quiet) { 1696 ClassInfo info = new ClassInfo(); 1697 info.cmd = cmd; 1698 classInfoMap.put(cmd, info); 1699 JdbcClass jdbcClass = new JdbcClass(sqlDriver); 1700 cmd.storeClass = jdbcClass; 1701 jdbcClass.cmd = cmd; 1702 JdoClass jdoClass = cmd.jdoClass; 1703 1704 jdbcClass.optimisticLocking = jdbcConfig.jdbcOptimisticLocking; 1706 info.optimisticLockingExt = null; 1707 1708 jdbcClass.useJoin = JdbcRefField.USE_JOIN_OUTER; 1709 jdbcClass.doNotCreateTable = jdbcConfig.jdbcDoNotCreateTable; 1710 1711 switch (jdbcConfig.defaultClassId) { 1713 case JdbcConfig.DEFAULT_CLASS_ID_FULLNAME: 1714 jdbcClass.jdbcClassId = cmd.qname; 1715 break; 1716 case JdbcConfig.DEFAULT_CLASS_ID_NAME: 1717 jdbcClass.jdbcClassId = cmd.jdoClass.name; 1718 break; 1719 default: 1720 jdbcClass.jdbcClassId = cmd.classIdString; 1721 } 1722 1723 if (cmd.pcSuperMetaData != null) { 1724 if (getClassInfo(cmd.top).noClassIdCol) { 1725 jdbcClass.inheritance = JdbcClass.INHERITANCE_VERTICAL; 1726 } else { 1727 jdbcClass.inheritance = jdbcConfig.inheritance; 1728 } 1729 } else { 1730 jdbcClass.inheritance = jdbcConfig.inheritance; 1731 info.noClassIdCol = jdbcConfig.defaultClassId == JdbcConfig.DEFAULT_CLASS_ID_NO; 1732 } 1733 1734 if (cmd.identityType == MDStatics.IDENTITY_TYPE_DATASTORE) { 1735 info.keyGenFactory = keyGenRegistry.getFactory( 1736 jdbcConfig.jdbcKeyGenerator); 1737 info.keyGenFactoryArgs = info.keyGenFactory.createArgsBean(); 1738 BeanUtils.setProperties(info.keyGenFactoryArgs, 1739 jdbcConfig.jdbcKeyGeneratorProps); 1740 } 1741 1742 JdoElement[] elements = jdoClass.elements; 1744 int n = elements.length; 1745 ArrayList jdbcElements = info.elements = new ArrayList(n); 1746 for (int i = 0; i < n; i++) { 1747 JdoElement o = elements[i]; 1748 if (o instanceof JdoExtension) { 1749 try { 1750 processClassExtensionPass1(cmd, (JdoExtension)o, 1751 jdbcElements, quiet); 1752 } catch (RuntimeException e) { 1753 cmd.addError(e, quiet); 1754 } 1755 } else { JdoField jdoField = (JdoField)o; 1757 FieldMetaData fmd = cmd.getFieldMetaData(jdoField.name); 1758 if (fmd == null) continue; 1760 if (fmd.isEmbeddedRef()) { 1761 continue; 1762 } 1763 1764 JdbcField f = null; 1765 f = createJdbcField(fmd, quiet); 1766 if (f != null) { 1767 f.fmd = fmd; 1768 fmd.storeField = f; 1769 fmd.primaryField = true; 1770 jdbcElements.add(f); 1771 } 1772 } 1773 } 1774 1775 FieldMetaData[] fields = cmd.fields; 1777 n = fields.length; 1778 for (int i = 0; i < n; i++) { 1779 FieldMetaData fmd = fields[i]; 1780 if (fmd.storeField != null || fmd.isEmbeddedRef()) continue; 1781 JdbcField f = createJdbcField(fmd, quiet); 1782 if (f != null) { 1783 f.fmd = fmd; 1784 fmd.storeField = f; 1785 fmd.primaryField = true; 1786 jdbcElements.add(f); 1787 } 1788 } 1789 1790 cmd.changedOptimisticLocking = 1791 jdbcClass.optimisticLocking == JdbcClass.OPTIMISTIC_LOCKING_CHANGED; 1792 1793 if (cmd.pcSubclasses != null) { 1795 for (int i = cmd.pcSubclasses.length - 1; i >= 0; i--) { 1796 createJdbcClass(cmd.pcSubclasses[i], quiet); 1797 } 1798 } 1799 } 1800 1801 1806 private void processClassIdCol(ClassMetaData cmd, boolean quiet, 1807 HashMap classIdMap) { 1808 ClassInfo info = getClassInfo(cmd); 1809 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 1810 1811 if (cmd.pcSuperMetaData == null) { 1812 if (!info.noClassIdCol && cmd.pcSubclasses != null) { 1813 boolean intClassId = jdbcClass.isIntJdbcClassIdHeirachy(); 1815 Class javaType = intClassId ? (Class )Integer.TYPE : (Class )String .class; 1816 1817 if (info.classIdExt != null && info.classIdExt.nested != null) { 1818 JdbcColumn col = jdbcClass.classIdCol = createColumn(info.classIdExt.nested, CLASS_ID_FIELDNAME, 1821 javaType); 1822 if (col.pk) { 1823 throw BindingSupportImpl.getInstance().runtime("The jdbc-primary-key option is " + 1824 "not allowed for a jdbc-class-id column\n" + 1825 info.classIdExt.getContext()); 1826 } 1827 info.elements.add(col); 1828 } else { 1829 jdbcClass.classIdCol = createColumn(null, 1831 CLASS_ID_FIELDNAME, javaType); 1832 info.elements.add(jdbcClass.classIdCol); 1833 } 1834 1835 if (intClassId) jdbcClass.convertJdbcClassIdToInteger(); 1837 } else { 1838 jdbcClass.jdbcClassId = null; 1839 } 1840 } else { if (getClassInfo(cmd.top).noClassIdCol) { 1842 if (jdbcClass.inheritance != JdbcClass.INHERITANCE_VERTICAL) { 1843 if (cmd.pcSuperMetaData.pcSubclasses.length > 1) { 1849 throw BindingSupportImpl.getInstance().invalidOperation( 1850 "Class " + cmd.qname + 1851 " must use vertical inheritance as\n" + 1852 "it has siblings and the base class " + 1853 "does not have a descriminator (jdo_class) column\n" + 1854 cmd.jdoClass.getContext()); 1855 } 1856 cmd.pcSuperMetaData.instancesNotAllowed = true; 1858 for (ClassMetaData i = cmd.pcSuperMetaData; i != null; 1860 i = i.pcSuperMetaData) { 1861 ((JdbcClass)i.storeClass).readAsClass = cmd; 1862 } 1863 } 1864 jdbcClass.jdbcClassId = null; 1865 } 1866 1867 jdbcClass.classIdCol = ((JdbcClass)cmd.top.storeClass).classIdCol; 1869 } 1870 1871 if (jdbcClass.jdbcClassId != null) { 1873 ClassMetaData other = 1874 (ClassMetaData)classIdMap.get(jdbcClass.jdbcClassId); 1875 if (other != null) { 1876 throw BindingSupportImpl.getInstance().invalidOperation("Class " + cmd.qname + 1877 " has same jdbc-class-id as " + other.qname + ": '" + 1878 jdbcClass.jdbcClassId + "'\n" + 1879 cmd.jdoClass.getContext()); 1880 } 1881 classIdMap.put(jdbcClass.jdbcClassId, cmd); 1882 } 1883 1884 if (cmd.pcSubclasses != null) { 1886 ClassMetaData[] subs = cmd.pcSubclasses; 1887 for (int i = 0; i < subs.length; i++) { 1888 processClassIdCol(subs[i], quiet, classIdMap); 1889 } 1890 } 1891 } 1892 1893 1898 private JdbcField createJdbcField(FieldMetaData fmd, 1899 boolean quiet) { 1900 try { 1901 switch (fmd.category) { 1902 case MDStatics.CATEGORY_TRANSACTIONAL: 1903 return null; 1904 case MDStatics.CATEGORY_SIMPLE: 1905 return createJdbcSimpleField(fmd); 1906 case MDStatics.CATEGORY_REF: 1907 return new JdbcRefField(); 1908 case MDStatics.CATEGORY_POLYREF: 1909 return new JdbcPolyRefField(); 1910 case MDStatics.CATEGORY_COLLECTION: 1911 return createJdbcCollectionField(fmd); 1912 case MDStatics.CATEGORY_ARRAY: 1913 return createFieldForArray(fmd); 1914 case MDStatics.CATEGORY_MAP: 1915 return new JdbcMapField(); 1916 case MDStatics.CATEGORY_EXTERNALIZED: 1917 return createJdbcSerializedField(fmd); 1918 } 1919 throw BindingSupportImpl.getInstance().internal("Field " + fmd.name + " of " + 1920 fmd.classMetaData.qname + 1921 " has bad category: " + 1922 MDStaticUtils.toCategoryString(fmd.category)); 1923 } catch (RuntimeException e) { 1924 fmd.addError(e, quiet); 1925 } 1926 return null; 1927 } 1928 1929 private JdbcCollectionField createJdbcCollectionField(FieldMetaData fmd) { 1930 return createJdbcField(fmd, 1931 fmd.jdoCollection == null ? null : fmd.jdoCollection.extensions); 1932 } 1933 1934 private JdbcCollectionField createJdbcField(FieldMetaData fmd, 1935 JdoExtension[] exts) { 1936 if (exts != null) { 1937 JdoExtension[] a = exts; 1941 int n = a == null ? 0 : a.length; 1942 boolean gotLink = false; 1943 JdoExtension ie = null; 1944 for (int i = 0; i < n; i++) { 1945 JdoExtension e = a[i]; 1946 switch (e.key) { 1947 case INVERSE: 1948 case JDBC_LINK_FOREIGN_KEY: 1949 if (ie != null || gotLink) { 1950 throw BindingSupportImpl.getInstance().runtime("The " + (ie != null ? "inverse" : "jdbc-link-table") + 1951 " extension has already been specified\n" + 1952 e.getContext()); 1953 } 1954 ie = e; 1955 break; 1956 case JDBC_LINK_TABLE: 1957 if (ie != null || gotLink) { 1958 throw BindingSupportImpl.getInstance().runtime("The " + (ie != null ? "inverse" : "jdbc-link-table") + 1959 " extension has already been specified\n" + 1960 e.getContext()); 1961 } 1962 gotLink = true; 1963 break; 1964 } 1965 } 1966 if (ie != null) { 1967 ClassMetaData ecmd = fmd.elementTypeMetaData; 1970 if (ecmd == null) { 1971 throw BindingSupportImpl.getInstance().runtime("The inverse extension may only be used for " + 1972 "collections of PC instances\n" + ie.getContext()); 1973 } 1974 String fname = ie.getString(); 1975 FieldMetaData f = ecmd.getFieldMetaData(fname); 1976 if (f == null) { 1977 if (fname != null && (fname.equals("") || fname.equals( 1978 FieldMetaData.NO_FIELD_TEXT))) { 1979 return new JdbcFKCollectionField(); 1980 } else { 1981 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' not found on " + 1982 fmd.elementType + "\n" + ie.getContext()); 1983 } 1984 } 1985 switch (f.category) { 1986 case MDStatics.CATEGORY_REF: 1987 return new JdbcFKCollectionField(); 1988 case MDStatics.CATEGORY_ARRAY: 1989 case MDStatics.CATEGORY_COLLECTION: 1990 return new JdbcLinkCollectionField(); 1991 } 1992 throw BindingSupportImpl.getInstance().runtime("Field '" + fname + "' is not a reference, collection or array\n" + 1993 ie.getContext()); 1994 } 1995 } 1996 return new JdbcLinkCollectionField(); 1997 } 1998 1999 private JdbcSimpleField createJdbcSimpleField(FieldMetaData fmd) { 2000 JdbcSimpleField f = new JdbcSimpleField(); 2001 JdoField jdoField = fmd.jdoField; 2002 JdoExtension[] a = jdoField == null ? null : jdoField.extensions; 2003 int n = a == null ? 0 : a.length; 2004 for (int i = 0; i < n; i++) { 2005 JdoExtension e = a[i]; 2006 switch (e.key) { 2007 case JDBC_COLUMN: 2008 break; 2010 default: 2011 if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e); 2012 } 2013 } 2014 f.col = createColumn(a, fmd.name, fmd.type); 2015 f.col.comment = fmd.getCommentName(); 2016 if ((f.col.pk = fmd.primaryKey) 2017 || fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) { 2018 f.col.nulls = false; 2019 } else if (fmd.nullValue == MDStatics.NULL_VALUE_NONE) { 2020 f.col.nulls = true; 2021 } 2022 if (fmd.embeddedFakeField) { 2023 f.col.nulls = true; 2024 } 2025 f.includeForChangedLocking = f.col.equalityTest; 2026 return f; 2027 } 2028 2029 private JdbcSimpleField createJdbcSerializedField(FieldMetaData fmd) { 2030 JdbcSimpleField f = new JdbcSimpleField(); 2031 JdoField jdoField = fmd.jdoField; 2032 JdoExtension[] a = jdoField == null ? null : jdoField.extensions; 2033 int n = a == null ? 0 : a.length; 2034 for (int i = 0; i < n; i++) { 2035 JdoExtension e = a[i]; 2036 switch (e.key) { 2037 case JDBC_COLUMN: 2038 break; 2040 default: 2041 if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e); 2042 } 2043 } 2044 f.col = createColumn(a, fmd.name, 2045 fmd.externalizer.getExternalType()); 2046 f.col.comment = fmd.getCommentName(); 2047 if (fmd.nullValue == MDStatics.NULL_VALUE_EXCEPTION) { 2048 f.col.nulls = false; 2049 } else if (fmd.nullValue == MDStatics.NULL_VALUE_NONE) { 2050 f.col.nulls = true; 2051 } 2052 f.includeForChangedLocking = f.col.equalityTest; 2053 return f; 2054 } 2055 2056 2060 private JdbcField createFieldForArray(FieldMetaData fmd) { 2061 if (fmd.embedded) { 2062 return createJdbcSimpleField(fmd); 2063 } else { 2064 return createJdbcField(fmd, 2065 fmd.jdoArray == null ? null : fmd.jdoArray.extensions); 2066 } 2067 } 2068 2069 2077 private void processClassExtensionPass1(ClassMetaData cmd, JdoExtension e, 2078 ArrayList jdbcElements, boolean quiet) { 2079 JdbcClass jdbcClass = (JdbcClass)cmd.storeClass; 2080 ClassInfo info; 2081 switch (e.key) { 2082 case DATASTORE: 2083 break; 2085 case JDBC_INHERITANCE: 2086 try { 2094 if (e.value != null) { 2095 jdbcClass.inheritance = e.getEnum(jdbcMDE.INHERITANCE_ENUM); 2096 } 2097 getClassInfo(cmd).inheritance = e; 2098 } catch (RuntimeException x) { 2099 cmd.addError(x, quiet); 2100 } 2101 break; 2102 case JDBC_TABLE_NAME: 2103 if (jdbcClass.tableName != null) { 2104 RuntimeException x = BindingSupportImpl.getInstance().runtime("Class " + 2105 cmd.qname + " already has a jdbc-table-name: " + 2106 jdbcClass.tableName + "\n" + 2107 e.getContext()); 2108 cmd.addError(x, quiet); 2109 } 2110 jdbcClass.tableName = e.getString(); 2111 break; 2112 case JDBC_KEY_GENERATOR: 2113 if (cmd.pcSuperMetaData != null) { 2114 RuntimeException x = BindingSupportImpl.getInstance().runtime("The jdbc-key-generator extension is only allowed for " + 2115 "the least derived class in a heirachy\n" + 2116 e.getContext()); 2117 cmd.addError(x, quiet); 2118 } 2119 info = getClassInfo(cmd); 2120 if (e.value != null) { 2121 JdbcKeyGeneratorFactory f = findKeyGenFactory(e); 2122 if (info.keyGenFactory != f) { 2123 info.keyGenFactory = f; 2124 info.keyGenFactoryArgs = f.createArgsBean(); 2125 } 2126 } else if (info.keyGenFactory == null) { 2127 RuntimeException x = BindingSupportImpl.getInstance().runtime("The jdbc-key-generator extension must specify a factory " + 2128 "for application identity classes\n" + 2129 e.getContext()); 2130 cmd.addError(x, quiet); 2131 } 2132 BeanUtils.setProperties(info.keyGenFactoryArgs, 2133 e.getPropertyMap()); 2134 break; 2135 case JDBC_INDEX: 2136 try { 2137 info = getClassInfo(cmd); 2138 info.indexExts.add(e); 2139 } catch (RuntimeException x) { 2140 cmd.addError(x, quiet); 2141 } 2142 break; 2143 case JDBC_OPTIMISTIC_LOCKING: 2144 try { 2145 processClassOptimisticLocking(e, jdbcClass, cmd, quiet); 2146 } catch (RuntimeException x) { 2147 cmd.addError(x, quiet); 2148 } 2149 break; 2150 case JDBC_CLASS_ID: 2151 try { 2152 processJdbcClassIdExtension(cmd, e, jdbcClass); 2153 } catch (RuntimeException x) { 2154 cmd.addError(x, quiet); 2155 } 2156 break; 2157 case JDBC_COLUMN: 2158 try { 2159 processClassColumnExtension(e, cmd, 2160 jdbcElements); 2161 } catch (RuntimeException x) { 2162 cmd.addError(x, quiet); 2163 } 2164 break; 2165 case JDBC_PRIMARY_KEY: 2166 try { 2167 processClassPrimaryKeyExtension(e, cmd, 2168 jdbcElements); 2169 } catch (RuntimeException x) { 2170 cmd.addError(x, quiet); 2171 } 2172 break; 2173 case JDBC_PK_FK_CONSTRAINT_NAME: 2174 info = getClassInfo(cmd); 2175 if (info.pkFkConstraintName != null) { 2176 RuntimeException x = BindingSupportImpl.getInstance().runtime("The jdbc-pk-fk-constraint extension may only appear once\n" + 2177 e.getContext()); 2178 cmd.addError(x, quiet); 2179 } 2180 info.pkFkConstraintName = e.getString(); 2181 break; 2182 case JDBC_USE_JOIN: 2183 try { 2184 jdbcClass.useJoin = e.getEnum(jdbcMDE.USE_JOIN_ENUM); 2185 } catch (RuntimeException x) { 2186 cmd.addError(x, quiet); 2187 } 2188 break; 2189 case JDBC_DO_NOT_CREATE_TABLE: 2190 try { 2191 jdbcClass.doNotCreateTable = e.getBoolean(); 2192 } catch (RuntimeException x) { 2193 cmd.addError(x, quiet); 2194 } 2195 break; 2196 default: 2197 if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e); 2198 } 2199 } 2200 2201 private void processJdbcClassIdExtension(ClassMetaData cmd, JdoExtension e, 2202 JdbcClass jdbcClass) { 2203 ClassInfo info; 2204 info = getClassInfo(cmd); 2205 if (info.classIdExt != null) { 2206 throw BindingSupportImpl.getInstance().invalidOperation("The jdbc-class-id extension may " + 2207 "only be specified once\n" + e.getContext()); 2208 } 2209 info.classIdExt = e; 2210 if (e.value != null) { 2211 info.noClassIdCol = false; 2212 if (e.isNoValue()) { 2213 if (cmd.pcSuperMetaData != null) { 2214 throw BindingSupportImpl.getInstance().invalidOperation(JdoExtension.NO_VALUE + " is only valid " + 2215 "for the least derived class in the " + 2216 "heircachy:\n" + e.getContext()); 2217 } 2218 info.noClassIdCol = true; 2219 } else if (JdoExtension.NAME_VALUE.equals(e.value)) { 2220 jdbcClass.jdbcClassId = cmd.jdoClass.name; 2221 } else if (JdoExtension.FULLNAME_VALUE.equals(e.value)) { 2222 jdbcClass.jdbcClassId = cmd.qname; 2223 } else { 2224 jdbcClass.jdbcClassId = e.value; 2225 } 2226 } 2227 if (e.nested != null) { 2228 if (cmd.pcSuperMetaData != null) { 2229 throw BindingSupportImpl.getInstance().runtime("The jdbc-class-id extension may " + 2230 "only define a column for the least derived class in the " + 2231 "heirachy\n" + e.getContext()); 2232 } 2233 } 2234 } 2235 2236 private void processClassOptimisticLocking(JdoExtension e, 2237 JdbcClass jdbcClass, ClassMetaData cmd, boolean quiet) { 2238 if (cmd.pcSuperMetaData != null) { 2239 RuntimeException x = BindingSupportImpl.getInstance().runtime("The jdbc-optimistic-locking " + 2240 "option may only be specified for the least derived class " + 2241 "in a heirachy\n" + e.getContext()); 2242 cmd.addError(x, quiet); 2243 } 2244 if (e.value != null) { 2245 try { 2246 jdbcClass.optimisticLocking = e.getEnum( 2247 jdbcMDE.OPTIMISTIC_LOCKING_ENUM); 2248 } catch (RuntimeException x) { 2249 cmd.addError(x, quiet); 2250 } 2251 } 2252 getClassInfo(cmd).optimisticLockingExt = e; 2253 } 2254 2255 private void processClassColumnExtension(JdoExtension e, ClassMetaData cmd, 2256 ArrayList jdbcElements) { 2257 JdbcColumn col = createColumn(e.nested, 2258 CLASS_ID_FIELDNAME, Integer.TYPE); 2259 JdbcSimpleField f = new JdbcSimpleField(); 2260 f.fake = true; 2261 f.col = col; 2262 FieldMetaData fmd = f.fmd = new FieldMetaData(); 2263 fmd.fake = true; 2264 fmd.category = MDStatics.CATEGORY_SIMPLE; 2265 fmd.classMetaData = cmd; 2266 fmd.defaultFetchGroup = true; 2267 fmd.storeField = f; 2268 fmd.name = "jdo" + jdbcElements.size(); 2269 fmd.persistenceModifier = MDStatics.PERSISTENCE_MODIFIER_PERSISTENT; 2270 fmd.setType(col.javaType); 2271 jdbcElements.add(f); 2272 } 2273 2274 private void processClassPrimaryKeyExtension(JdoExtension e, 2275 ClassMetaData cmd, ArrayList jdbcElements) { 2276 if (cmd.identityType != MDStatics.IDENTITY_TYPE_DATASTORE) { 2277 throw BindingSupportImpl.getInstance().runtime("jdbc-primary-key only allowed for classes " + 2278 "with identity-type 'datastore'\n" + 2279 e.getContext()); 2280 } 2281 2282 ClassInfo info; 2283 JdoExtension[] a = e.nested; 2284 int n = a == null ? 0 : a.length; 2285 for (int i = 0; i < n; i++) { 2286 JdoExtension f = a[i]; 2287 switch (f.key) { 2288 case JDBC_COLUMN: 2289 break; 2291 case JDBC_CONSTRAINT: 2292 info = getClassInfo(cmd); 2293 if (info.pkConstraintName != null) { 2294 throw BindingSupportImpl.getInstance().runtime("The jdbc-constraint extension may only appear once\n" + 2295 e.getContext()); 2296 } 2297 info.pkConstraintName = e.getString(); 2298 break; 2299 default: 2300 if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e); 2301 } 2302 } 2303 2304 JdbcColumn col = createColumn(a, 2305 DATASTORE_PK_FIELDNAME, Integer.TYPE); 2306 col.pk = true; 2307 col.nulls = false; 2308 jdbcElements.add(col); 2309 } 2310 2311 2315 private JdbcKeyGeneratorFactory findKeyGenFactory(JdoExtension e) { 2316 String fname = e.getString(); 2317 try { 2318 return keyGenRegistry.getFactory(fname); 2319 } catch (Exception x) { 2320 throw BindingSupportImpl.getInstance().runtime(x.getMessage() + 2321 "\n" + e.getContext(), x); 2322 } 2323 } 2324 2325 2328 private JdbcConverterFactory createJdbcConverterFactory(JdoExtension e) { 2329 try { 2330 return converterRegistry.getFactory(e.getString()); 2331 } catch (Exception x) { 2332 throw BindingSupportImpl.getInstance().runtime( 2333 "Unable to create JdbcConverterFactory\n" + e.getContext(), 2334 x); 2335 } 2336 } 2337 2338 2348 public JdbcColumn createColumn(JdoExtension[] nested, JdbcColumn base) { 2349 2350 nested = findMatchingJdbcColumn(nested); 2352 2353 JdbcColumn c = base.copy(); 2355 if (nested != null) { 2356 JdbcJavaTypeMapping m = createFieldMapping(nested); 2357 mappingResolver.fillMappingForJdbcType(m); 2358 c.updateFrom(m, mappingResolver); 2359 updateColumnName(nested, c); 2360 updateConverter(nested, c); 2361 } 2362 return c; 2363 } 2364 2365 2373 public JdbcColumn createColumn(JdoExtension[] nested, 2374 String fieldName, Class javaType) { 2375 2376 nested = findMatchingJdbcColumn(nested); 2378 2379 JdbcJavaTypeMapping m = createFieldMapping(nested); 2381 m = mappingResolver.resolveMapping(m, fieldName, javaType); 2382 JdbcColumn c = new JdbcColumn(m, mappingResolver); 2383 updateColumnName(nested, c); 2384 updateConverter(nested, c); 2385 c.comment = fieldName; 2386 return c; 2387 } 2388 2389 2392 private void updateConverter(JdoExtension[] nested, 2393 JdbcColumn c) { 2394 if (nested != null) { 2395 boolean done = false; 2396 int n = nested.length; 2397 for (int i = 0; i < n; i++) { 2398 JdoExtension e = nested[i]; 2399 if (e.key == JDBC_CONVERTER) { 2400 if (done) { 2401 throw BindingSupportImpl.getInstance().runtime("jdbc-converter extension has already been used\n" + 2402 e.getContext()); 2403 } 2404 JdbcConverterFactory f = createJdbcConverterFactory(e); 2405 HashMap p = e.getPropertyMap(); 2406 try { 2407 c.converter = f.createJdbcConverter(c, p, 2408 mappingResolver); 2409 } catch (IllegalArgumentException x) { 2410 throw BindingSupportImpl.getInstance().runtime("Unable to create JdbcConverter\n" + 2411 e.getContext(), x); 2412 } 2413 done = true; 2414 } 2415 } 2416 } 2417 } 2418 2419 2422 private void updateColumnName(JdoExtension[] nested, JdbcColumn c) { 2423 if (nested != null) { 2424 int n = nested.length; 2425 for (int i = 0; i < n; i++) { 2426 JdoExtension e = nested[i]; 2427 if (e.key != JDBC_COLUMN_NAME) continue; 2428 if (c.name != null) { 2429 throw BindingSupportImpl.getInstance().runtime("Only one jdbc-column-name extension is allowed\n" + 2430 e.getContext()); 2431 } 2432 c.name = e.getString(); 2433 } 2434 } 2435 } 2436 2437 2443 private JdoExtension[] findMatchingJdbcColumn(JdoExtension[] nested) { 2444 if (nested != null) { 2445 JdoExtension matchGeneral = null; 2446 JdoExtension matchSpecific = null; 2447 String sdb = sqlDriver.getName(); 2448 int n = nested.length; 2449 for (int i = 0; i < n; i++) { 2450 JdoExtension e = nested[i]; 2451 if (e.key != JDBC_COLUMN) continue; 2452 String db = e.value; 2453 if (db == null) { 2454 if (matchGeneral != null) { 2455 throw BindingSupportImpl.getInstance().runtime("Only one all databases jdbc-column extension is allowed\n" + 2456 e.getContext()); 2457 } 2458 matchGeneral = e; 2459 } else if (db.equals(sdb)) { 2460 if (matchSpecific != null) { 2461 throw BindingSupportImpl.getInstance().runtime("Only one jdbc-column extension is allowed per database\n" + 2462 e.getContext()); 2463 } 2464 matchSpecific = e; 2465 } 2466 } 2467 if (matchSpecific != null) { 2468 nested = matchSpecific.nested; 2469 } else if (matchGeneral != null) { 2470 nested = matchGeneral.nested; 2471 } else { 2472 nested = null; 2473 } 2474 } 2475 return nested; 2476 } 2477 2478 2483 private JdbcJavaTypeMapping createFieldMapping(JdoExtension[] nested) { 2484 JdbcJavaTypeMapping m = new JdbcJavaTypeMapping(); 2485 if (nested == null) return m; 2486 int n = nested.length; 2487 for (int i = 0; i < n; i++) { 2488 JdoExtension e = nested[i]; 2489 switch (e.key) { 2490 case JDBC_COLUMN_NAME: 2491 if (m.getColumnName() != null) { 2492 throw BindingSupportImpl.getInstance().runtime("jdbc-column-name has already been set\n" + 2493 e.getContext()); 2494 } 2495 m.setColumnName(e.getString()); 2496 break; 2497 case JDBC_TYPE: 2498 if (m.getJdbcType() != 0) { 2499 throw BindingSupportImpl.getInstance().runtime("jdbc-type has already been set\n" + 2500 e.getContext()); 2501 } 2502 m.setJdbcType(getJdbcType(e)); 2503 break; 2504 case JDBC_SQL_TYPE: 2505 if (m.getSqlType() != null) { 2506 throw BindingSupportImpl.getInstance().runtime("jdbc-sql-type has already been set\n" + 2507 e.getContext()); 2508 } 2509 m.setSqlType(e.getString()); 2510 break; 2511 case JDBC_LENGTH: 2512 if (m.getLength() >= 0) { 2513 throw BindingSupportImpl.getInstance().runtime("jdbc-length has already been set\n" + 2514 e.getContext()); 2515 } 2516 m.setLength(e.getInt()); 2517 break; 2518 case JDBC_SCALE: 2519 if (m.getScale() >= 0) { 2520 throw BindingSupportImpl.getInstance().runtime("jdbc-scale has already been set\n" + 2521 e.getContext()); 2522 } 2523 m.setScale(e.getInt()); 2524 break; 2525 case JDBC_NULLS: 2526 if (m.getNulls() != JdbcJavaTypeMapping.NOT_SET) { 2527 throw BindingSupportImpl.getInstance().runtime("jdbc-nulls has already been set\n" + 2528 e.getContext()); 2529 } 2530 m.setNulls(e.getBoolean()); 2531 break; 2532 case JDBC_SHARED: 2533 break; 2535 case JDBC_JAVA_TYPE: 2536 if (m.getJavaType() != null) { 2537 throw BindingSupportImpl.getInstance().runtime("jdbc-java-type has already been set\n" + 2538 e.getContext()); 2539 } 2540 m.setJavaType(e.getType(loader)); 2541 break; 2542 case JDBC_CONVERTER: 2543 break; 2545 default: 2546 if (e.isJdbc()) MetaDataBuilder.throwUnexpectedExtension(e); 2547 break; 2548 } 2549 } 2550 return m; 2551 } 2552 2553 2558 public int getJdbcType(JdoExtension e) { 2559 try { 2560 return JdbcTypes.parse(e.getString()); 2561 } catch (IllegalArgumentException x) { 2562 throw BindingSupportImpl.getInstance().runtime(x.getMessage() + 2563 "\n" + e.getContext()); 2564 } 2565 } 2566 2567 public ModelMetaData getJmd() { 2568 return jmd; 2569 } 2570 2571 public SqlDriver getSqlDriver() { 2572 return sqlDriver; 2573 } 2574 2575 public JdbcMappingResolver getMappingResolver() { 2576 return mappingResolver; 2577 } 2578 2579 protected void setMasterDetailFlags(ClassMetaData[] classes) { 2580 if (Debug.DEBUG) { 2581 System.out.println( 2582 "MDB-JDBC: Setting master detail flags"); 2583 } 2584 int clen = classes.length; 2585 for (int i = 0; i < clen; i++) { 2586 ClassMetaData cmd = classes[i]; 2587 if (cmd.stateFields == null) continue; for (int j = 0; j < cmd.stateFields.length; j++) { 2589 FieldMetaData fmd = cmd.stateFields[j]; 2590 switch (fmd.category) { 2591 case MDStatics.CATEGORY_REF: 2592 JdbcField jdbcField = (JdbcField)fmd.storeField; 2593 if (jdbcField != null) { JdbcFKCollectionField masterField = 2595 ((JdbcRefField)jdbcField).masterCollectionField; 2596 if (masterField != null) { 2597 fmd.inverseFieldMetaData = masterField.fmd; 2598 fmd.isDetail = true; 2599 fmd.managed = masterField.fmd.managed; 2600 } 2601 } 2602 break; 2603 case MDStatics.CATEGORY_COLLECTION: 2604 if (fmd.storeField instanceof JdbcFKCollectionField) { 2605 fmd.inverseFieldMetaData = ((JdbcFKCollectionField)fmd.storeField).fkField.fmd; 2606 fmd.isMaster = true; 2607 } 2608 break; 2609 } 2610 } 2611 } 2612 } 2613 2614 protected void calcSuperCounts(ClassMetaData[] classes) { 2615 super.calcSuperCounts(classes); 2616 for (int j = 0; j < classes.length; j++) { 2619 ClassMetaData cmd = classes[j]; 2620 if (cmd == null || cmd.stateFields == null) { 2621 continue; 2622 } 2623 int[] a = new int[cmd.stateFields.length]; 2624 int c = 0; 2625 for (int i = cmd.stateFields.length - 1; i >= 0; i--) { 2626 FieldMetaData f = cmd.stateFields[i]; 2627 if (f.storeField instanceof JdbcRefField) { 2628 JdbcRefField rf = (JdbcRefField)f.storeField; 2629 if (rf.masterCollectionField != null) { 2630 a[c++] = i; 2631 } 2632 } 2633 } 2634 if (c > 0) { 2635 int[] b = new int[c]; 2636 System.arraycopy(a, 0, b, 0, c); 2637 cmd.fkCollectionRefStateFieldNos = b; 2638 } else { 2639 cmd.fkCollectionRefStateFieldNos = null; 2640 } 2641 } 2642 } 2643 2644} 2645 | Popular Tags |