001package gu.sql2java.generator; 002 003import java.security.MessageDigest; 004import java.security.NoSuchAlgorithmException; 005import java.sql.DatabaseMetaData; 006import java.util.ArrayList; 007import java.util.Arrays; 008import java.util.Collection; 009import java.util.Collections; 010import java.util.Date; 011import java.util.HashMap; 012import java.util.HashSet; 013import java.util.Hashtable; 014import java.util.Iterator; 015import java.util.LinkedHashMap; 016import java.util.LinkedHashSet; 017import java.util.List; 018import java.util.Map.Entry; 019import java.util.Random; 020import java.util.Vector; 021import org.apache.commons.lang.builder.EqualsBuilder; 022import org.apache.commons.lang.builder.HashCodeBuilder; 023import org.apache.commons.lang.builder.ToStringBuilder; 024 025import com.google.common.base.Function; 026import com.google.common.base.Joiner; 027import com.google.common.base.Predicate; 028import com.google.common.base.Strings; 029import com.google.common.collect.Collections2; 030import com.google.common.collect.ImmutableList; 031import com.google.common.collect.Iterators; 032import com.google.common.collect.Lists; 033import com.google.common.collect.Maps; 034import com.google.common.collect.Ordering; 035import com.google.common.collect.Sets; 036import com.google.common.primitives.Longs; 037 038import gu.sql2java.generator.CodeWriter; 039import gu.sql2java.generator.Column; 040import gu.sql2java.generator.Database; 041import gu.sql2java.generator.Index; 042import gu.sql2java.generator.Procedure; 043import gu.sql2java.generator.StringUtilities; 044 045import static com.google.common.base.Preconditions.checkNotNull; 046import static com.google.common.base.Preconditions.checkArgument; 047 048public class Table { 049 private Hashtable<String,Column> colHash = new Hashtable<String,Column>(); 050 private Vector<Column> cols = new Vector<Column>(); 051 private Hashtable<String,Index> indHash = new Hashtable<String,Index>(); 052 private Vector<Index> indices = new Vector<Index>(); 053 private Hashtable<String,Index> indUniqueHash = new Hashtable<String,Index>(); 054 private Vector<Index> uniqueIndices = new Vector<Index>(); 055 private Hashtable<String,Index> indNonUniHash = new Hashtable<String,Index>(); 056 private Vector<Index> nonUniqueIndices = new Vector<Index>(); 057 private Vector<Column> priKey = new Vector<Column>(); 058 private Column autoincrement; 059 private String catalog; 060 private String schema; 061 private String name; 062 private String type; 063 private String remarks; 064 private Database database; 065 private Vector<Column> foreignKeys = new Vector<Column>(); 066 private Vector<Column> importedKeys = new Vector<Column>(); 067 /** FK_NAME 为索引保存所有 foreign keys */ 068 private LinkedHashMap<String, ForeignKey> fkNameMap = new LinkedHashMap<String,ForeignKey>(); 069 private List<Procedure> procedures = new ArrayList<Procedure>(); 070 private HashMap<String,Procedure> procHash = new HashMap<String,Procedure>(); 071 private Random aleatorio = new Random(new Date().getTime()); 072 073 @Override 074 public String toString() { 075 return new ToStringBuilder(this) 076 .append("catalog",catalog) 077 .append("schema", schema) 078 .append("name", name) 079 .append("type", type) 080 .append("remarks", remarks) 081 .toString(); 082 } 083 084 @Override 085 public int hashCode() { 086 return new HashCodeBuilder() 087 .append(catalog) 088 .append(indices) 089 .append(name) 090 .append(schema) 091 .toHashCode(); 092 } 093 094 @Override 095 public boolean equals(Object obj) { 096 if(super.equals(obj))return true; 097 if(!(obj instanceof Table))return false; 098 Table other = (Table)obj; 099 return new EqualsBuilder() 100 .append(catalog, other.catalog) 101 .append(indices, other.indices) 102 .append(name, other.name) 103 .append(schema, other.schema) 104 .append(type, other.type) 105 .isEquals(); 106 } 107 108 public boolean isRelationTable() { 109 return this.foreignKeys.size() == 2; 110 } 111 112 /** 113 * 代替{@link #isRelationTable()},判断当前表是否为联接表 114 * @return 115 */ 116 public boolean isJunctionTable() { 117 if(fkNameMap.size() ==2){ 118 HashSet<Column> fkColumns = Sets.<Column>newHashSet(); 119 for(ForeignKey fks:fkNameMap.values()){ 120 fkColumns.addAll(fks.columns); 121 } 122 Vector<Column> pkColumns = getPrimaryKeysAsList(); 123 if(pkColumns.size() == fkColumns.size()){ 124 fkColumns.retainAll(getPrimaryKeysAsList()); 125 return fkColumns.size() ==pkColumns.size(); 126 } 127 } 128 return false; 129 } 130 /** 131 * 判断是否为联接表,且主键为两个字段 132 * @return 133 */ 134 public boolean isSampleJunctionTable() { 135 return isJunctionTable() && 2 == countPrimaryKeys(); 136 } 137 /** 138 * 判断外键是否为自引用 139 * @return 140 */ 141 public boolean isSelfRef(ForeignKey fk) { 142 if(null == fk)return false; 143 return fk.getForeignTable().equals(this); 144 } 145 /** 返回所有自引用外键 */ 146 public List<ForeignKey> getSelfRefKeys(){ 147 return ImmutableList.copyOf(Collections2.filter(this.fkNameMap.values(), new Predicate<ForeignKey>(){ 148 @Override 149 public boolean apply(ForeignKey input) { 150 return isSelfRef(input); 151 }})); 152 } 153 public boolean relationConnectsTo(Table otherTable) { 154 if (this.equals(otherTable)) { 155 return false; 156 } 157 int nbImported = this.importedKeys.size(); 158 for (int i = 0; i < nbImported; ++i) { 159 Column c = (Column) this.importedKeys.get(i); 160 if (!c.getTableName().equals(otherTable.getName())) 161 continue; 162 return true; 163 } 164 return false; 165 } 166 167 public Table[] linkedTables(Database pDatabase, Table pTable) { 168 Vector<Table> vector = new Vector<Table>(); 169 int nbImported = this.importedKeys.size(); 170 for (int iIndex = 0; iIndex < nbImported; ++iIndex) { 171 Table pTableToAdd; 172 Column pColumn = (Column) this.importedKeys.get(iIndex); 173 if (pColumn.getTableName().equals(pTable.getName()) 174 || vector.contains(pTableToAdd = pDatabase.getTable(pColumn.getTableName()))) 175 continue; 176 vector.add(pTableToAdd); 177 } 178 return vector.toArray(new Table[vector.size()]); 179 } 180 /** 181 * 代替 {@link #linkedTables(Database, Table)}<br> 182 * 对于联接表(junction)返回{@code pTable}联接的表<br> 183 * @param pTable 184 * @return 当前对象不是连接表或{@code pTable}不属于联接表时返回{@code null} 185 */ 186 public Table tableOfJunction(Table pTable) { 187 if(this.isJunctionTable()){ 188 for(ForeignKey fk:this.fkNameMap.values()){ 189 Table jtable = fk.getForeignTable(); 190 if(!jtable.equals(pTable)) 191 return jtable; 192 } 193 } 194 return null; 195 } 196 public Column getForeignKeyFor(Table pTable) { 197 int nbImported = this.importedKeys.size(); 198 for (int iIndex = 0; iIndex < nbImported; ++iIndex) { 199 Column pColumn = (Column) this.importedKeys.get(iIndex); 200 if (!pColumn.getTableName().equals(pTable.getName())) 201 continue; 202 return pColumn; 203 } 204 return null; 205 } 206 207 /** 返回当前对象的关联表 */ 208 public List<Table> getJunctionTables() { 209 List<Table> tabs = this.getDatabase().getJunctionTables(); 210 if(isJunctionTable()){ 211 // 当前表是关联表,则返回空 212 tabs.clear(); 213 return tabs; 214 } 215 for(Iterator<Table> itor = tabs.iterator();itor.hasNext();){ 216 Table table = itor.next(); 217 if(!table.getForeignTablesAsList().contains(this)){ 218 itor.remove(); 219 } 220 } 221 return tabs; 222 } 223 public void setCatalog(String catalog) { 224 this.catalog = catalog; 225 } 226 227 public void setSchema(String schema) { 228 this.schema = schema; 229 } 230 231 public void setName(String name) { 232 this.name = name; 233 } 234 235 public void setType(String type) { 236 this.type = type; 237 } 238 239 public void setRemarks(String remarks) { 240 if (remarks != null) { 241 this.remarks = remarks.replaceAll("/\\*", "SLASH*").replaceAll("\\*/", "*SLASH"); 242 } 243 } 244 245 public String getCatalog() { 246 return this.catalog; 247 } 248 249 public String getSchema() { 250 return this.schema; 251 } 252 253 public String getName() { 254 return this.name; 255 } 256 257 public String getType() { 258 return this.type; 259 } 260 261 public Column[] getColumns() { 262 return this.getColumnsAsList().toArray(new Column[this.cols.size()]); 263 } 264 public Vector<Column> getColumnsAsList() { 265 Collections.sort(this.cols); 266 return this.cols; 267 } 268 public List<Column> getColumnsExceptPrimaryAsList() { 269 return Lists.newArrayList(Collections2.filter(getColumnsAsList(), new Predicate<Column>(){ 270 @Override 271 public boolean apply(Column input) { 272 return !input.isPrimaryKey(); 273 }})); 274 } 275 public Column[] getColumnsExceptPrimary() { 276 return getColumnsExceptPrimaryAsList().toArray(new Column[0]); 277 } 278 public Column getColumn(String columnName) { 279 return (Column) this.colHash.get(columnName.toLowerCase()); 280 } 281 282 public void addColumn(Column column) { 283 this.colHash.put(column.getName().toLowerCase(), column); 284 this.cols.addElement(column); 285 } 286 287 public void removeColumn(Column column) { 288 this.cols.removeElement((Object) column); 289 this.colHash.remove(column.getName().toLowerCase()); 290 } 291 292 public Index[] getUniqueIndices() { 293 return this.uniqueIndices.toArray(new Index[this.uniqueIndices.size()]); 294 } 295 296 public Index[] getNonUniqueIndices() { 297 return this.nonUniqueIndices.toArray( new Index[this.nonUniqueIndices.size()]); 298 } 299 300 public int countIndices() { 301 return this.indices.size(); 302 } 303 304 public Index[] getIndices() { 305 return this.indices.toArray( new Index[this.indices.size()]); 306 } 307 public List<Index> getIndicesAsList(Boolean unique) { 308 Iterator<Index>itor = this.indices.iterator(); 309 if(Boolean.TRUE == unique) 310 itor = Iterators.filter(itor, new Predicate<Index>(){ 311 @Override 312 public boolean apply(Index arg0) { 313 return arg0.isUnique(); 314 }}); 315 return ImmutableList.copyOf(itor); 316 } 317 public List<Index> getIndicesAsList(){ 318 return getIndicesAsList(false); 319 } 320 public List<Index> getUniqueIndicesAsList(){ 321 return getIndicesAsList(true); 322 } 323 public Index getIndex(String indName) { 324 return (Index) this.indHash.get(indName.toLowerCase()); 325 } 326 327 public void addIndex(Index index) { 328 this.indHash.put(index.getName().toLowerCase(), index); 329 this.indices.add(index); 330 if (index.isUnique()) { 331 this.indUniqueHash.put(index.getName().toLowerCase(), index); 332 this.uniqueIndices.add(index); 333 } else { 334 this.indNonUniHash.put(index.getName().toLowerCase(), index); 335 this.nonUniqueIndices.add(index); 336 } 337 } 338 339 public void removeIndex(Index index) { 340 this.indices.remove((Object) index); 341 this.indHash.remove(index.getName().toLowerCase()); 342 if (index.isUnique()) { 343 this.uniqueIndices.remove((Object) index); 344 this.indUniqueHash.remove(index.getName().toLowerCase()); 345 } else { 346 this.nonUniqueIndices.remove((Object) index); 347 this.indNonUniHash.remove(index.getName().toLowerCase()); 348 } 349 } 350 351 public Column[] getPrimaryKeys() { 352 return this.priKey.toArray( new Column[this.priKey.size()]); 353 } 354 public Vector<Column> getPrimaryKeysAsList() { 355 return new Vector<Column>(this.priKey); 356 } 357 public boolean hasCompositeKey() { 358 if (this.priKey.size() > 1) { 359 return true; 360 } 361 return false; 362 } 363 364 public Column getPrimaryKey() throws RuntimeException { 365 if (this.priKey.size() != 1) { 366 throw new RuntimeException("Table " + this.getName() + " has a composite key, not a unique primary key"); 367 } 368 return (Column) this.priKey.get(0); 369 } 370 371 public void addPrimaryKey(Column column) { 372 this.priKey.addElement(column); 373 column.isPrimaryKey(true); 374 } 375 376 public Column[] getImportedKeys() { 377 return this.importedKeys.toArray( new Column[this.importedKeys.size()]); 378 } 379 380 public void addImportedKey(Column column) { 381 if (!this.importedKeys.contains((Object) column)) { 382 this.importedKeys.addElement(column); 383 } 384 } 385 386 public int countColumns() { 387 return this.cols.size(); 388 } 389 390 public int countPrimaryKeys() { 391 return this.priKey.size(); 392 } 393 394 public boolean hasPrimaryKey() { 395 return this.countPrimaryKeys() > 0; 396 } 397 398 public int countImportedKeys() { 399 return this.importedKeys.size(); 400 } 401 402 public boolean hasImportedKeys() { 403 return this.countImportedKeys() > 0; 404 } 405 406 public int countForeignKeys() { 407 return this.foreignKeys.size(); 408 } 409 410 public boolean hasForeignKeys() { 411 return this.countForeignKeys() > 0; 412 } 413 414 public void addForeignKey(Column col, 415 String fkName, 416 short keySeq, 417 Table.ForeignKeyRule updateRule, 418 Table.ForeignKeyRule deleteRule) { 419 checkNotNull(col); 420 checkArgument(!Strings.isNullOrEmpty(fkName)); 421 checkArgument(keySeq>0,"the argument 'keySeq' must >0"); 422 423 if (!this.foreignKeys.contains(col)) { 424 this.foreignKeys.add(col); 425 } 426 if(!this.fkNameMap.containsKey(fkName)) 427 this.fkNameMap.put(fkName, new ForeignKey(fkName,updateRule,deleteRule,col)); 428 Vector<Column> fkCols = fkNameMap.get(fkName).columns; 429 if(keySeq > fkCols.size()){ 430 fkCols.setSize(keySeq); 431 } 432 fkCols.set(keySeq-1, col); 433 } 434 435 /** 436 * 返回所有 foreign key name ( FK_NAME ) 437 * @return 438 */ 439 public Vector<String> getFkMapNames() { 440 return new Vector<String>(this.fkNameMap.keySet()); 441 } 442 443 /** 444 * 检索外键引用指定表(tableName)的所有 FK_NAME<br> 445 * 没有结果则返回空数组 446 * @param tableName 447 * @return 448 */ 449 public Vector<String> getFkMapNames(String tableName) { 450 Vector<String> names=new Vector<String>(); 451 for(ForeignKey fk:this.fkNameMap.values()){ 452 for(Column col:fk.columns.get(0).getForeignKeys()){ 453 if(col.getTableName().equals(tableName)){ 454 names.add(fk.fkName); 455 break; 456 } 457 } 458 } 459 Collections.sort(names); 460 461 return names; 462 } 463 464 /** 465 * 检索指定 FK_NAME 包含的所有字段<br> 466 * 没有结果则返回空数组 467 * @param fkName 468 * @return 469 */ 470 public Vector<Column> getForeignKeysByFkName(String fkName) { 471 ForeignKey keys=this.fkNameMap.get(fkName); 472 return null==keys?new Vector<Column>():new Vector<Column>(keys.columns); 473 } 474 475 /** 476 * 检索指定 FK_NAME 的{@link ForeignKey}对象<br> 477 * @param fkName 478 * @return 479 * @see java.util.concurrent.ConcurrentHashMap#get(java.lang.Object) 480 */ 481 public ForeignKey getForeignKey(String fkName) { 482 return fkNameMap.get(fkName); 483 } 484 485 /** 486 * 返回{@code table}对应的所有{@link ForeignKey}对象 487 * @param table 488 * @return 489 */ 490 public List<ForeignKey> getForeignKeys(final Table table){ 491 return Lists.newArrayList(Collections2.filter(this.fkNameMap.values(), new Predicate<ForeignKey>(){ 492 @Override 493 public boolean apply(ForeignKey input) { 494 return input.getForeignTable().equals(table); 495 }})); 496 } 497 public List<ForeignKey> getImportedFoeignKeysAsList(){ 498 ArrayList<ForeignKey> list = new ArrayList<ForeignKey>(); 499 for(Table table:getImportedTablesAsList()){ 500 list.addAll(table.getForeignKeys(this)); 501 } 502 return list; 503 } 504 public List<ForeignKey> getForeignKeysAsList(){ 505 return ImmutableList.copyOf(this.fkNameMap.values()); 506 } 507 /** 508 * 返回 所有需要输出foreign key listener的 {@link ForeignKey}对象 509 * @return 510 */ 511 public List<ForeignKey> getForeignKeysForListener(){ 512 Collection<ForeignKey> c = Maps.filterEntries(fkNameMap, 513 new Predicate<Entry<String, ForeignKey>>(){ 514 @Override 515 public boolean apply(Entry<String, ForeignKey> input) { 516 ForeignKey fk = input.getValue(); 517 return fk.updateRule.isNoAction() 518 && !Strings.isNullOrEmpty(fk.deleteRule.getEventOfDeleteRule()); 519 }}).values(); 520 // 排序输出 521 return Ordering.natural().onResultOf(new Function<ForeignKey,String>(){ 522 @Override 523 public String apply(ForeignKey input) { 524 return input.fkName; 525 }}).sortedCopy(c); 526 } 527 /** 528 * 判断 FK_NAME 包含的所有字段是否都允许为null 529 * @param fkName 530 * @return 531 */ 532 public boolean isNullable(String fkName){ 533 for(Column column: getForeignKeysByFkName(fkName)){ 534 if(column.isNotNull())return false; 535 } 536 return true; 537 } 538 /** 539 * 返回 FK_NAME 包含的所有字段中不允许为null的所有字段 540 * @param fkName 541 * @return 542 */ 543 public Vector<Column> noNullableColumns(String fkName){ 544 Vector<Column> keys = getForeignKeysByFkName(fkName); 545 for(Iterator<Column> itor = keys.iterator();itor.hasNext();){ 546 Column column = itor.next(); 547 if(DatabaseMetaData.columnNullable !=column.getNullable())continue; 548 itor.remove(); 549 } 550 return keys; 551 } 552 private String toUniversalFkName(String fkName) { 553 ForeignKey key = this.fkNameMap.get(fkName); 554 if(null!=key){ 555 return key.getUniversalName(); 556 } 557 return ""; 558 } 559 560 public Table getForeignTableByFkName(String fkName){ 561 Vector<Column> keys = this.getForeignKeysByFkName(fkName); 562 return 0==keys.size()? null:keys.get(0).getForeignColumn().getTable(); 563 } 564 public Column[] getForeignKeys() { 565 return this.foreignKeys.toArray( new Column[this.foreignKeys.size()]); 566 } 567 568 public boolean isForeignKey(Column col) { 569 return this.foreignKeys.contains((Object) col); 570 } 571 572 public int countManyToManyTables() { 573 return this.getManyToManyTables().length; 574 } 575 576 public boolean hasManyToManyTables() { 577 return this.countManyToManyTables() > 0; 578 } 579 580 public Table[] getManyToManyTables() { 581 Vector<Table> vector = new Vector<Table>(); 582 Table[] linkedTables = this.getImportedTables(); 583 System.out.println(this.getName() + " getManyToManyTables, linked tables = " + linkedTables.length); 584 for (int iIndex = 0; iIndex < linkedTables.length; ++iIndex) { 585 System.out.println(this.getName() + " " + linkedTables[iIndex].getName() + " relation table ?"); 586 if (!linkedTables[iIndex].isRelationTable()) 587 continue; 588 Table[] relationLinkedTable = linkedTables[iIndex].getForeignTables(); 589 System.out.println(this.getName() + " " + linkedTables[iIndex].getName() + " has " 590 + relationLinkedTable.length + " foreign table"); 591 for (int i = 0; i < relationLinkedTable.length; ++i) { 592 System.out.println(this.getName() + " " + i + " " + relationLinkedTable[i].getName() 593 + " is relation table"); 594 if (relationLinkedTable[i].equals(this) || vector.contains(relationLinkedTable[i])) 595 continue; 596 vector.add(relationLinkedTable[i]); 597 } 598 } 599 return vector.toArray(new Table[vector.size()]); 600 } 601 602 public int countLinkedTables() { 603 return this.getLinkedTables().length; 604 } 605 606 public boolean hasLinkedTables() { 607 return this.countLinkedTables() > 0; 608 } 609 610 public Table[] getLinkedTables() { 611 Vector<Table> vector = new Vector<Table>(); 612 int nbImported = this.importedKeys.size(); 613 for (int iIndex = 0; iIndex < nbImported; ++iIndex) { 614 Table pTableToAdd; 615 Column column = (Column) this.importedKeys.get(iIndex); 616 if (column.getTableName().equals(this.getName()) || vector.contains(pTableToAdd = column.getTable())) 617 continue; 618 vector.add(pTableToAdd); 619 } 620 int nbForeign = this.foreignKeys.size(); 621 for (int iIndex2 = 0; iIndex2 < nbForeign; ++iIndex2) { 622 Table pTableToAdd; 623 Column column = (Column) this.foreignKeys.get(iIndex2); 624 if ((column = column.getForeignColumn()).getTableName().equals(this.getName()) 625 || vector.contains(pTableToAdd = column.getTable())) 626 continue; 627 vector.add(pTableToAdd); 628 } 629 for(Table jtable:getJunctionTables()){ 630 Table pTableToAdd = jtable.tableOfJunction(this); 631 if(vector.contains(pTableToAdd)){ 632 continue; 633 } 634 vector.add(pTableToAdd); 635 } 636 return vector.toArray(new Table[vector.size()]); 637 } 638 639 public int countImportedTables() { 640 return this.getImportedTables().length; 641 } 642 643 public boolean hasImportedTables() { 644 return this.countImportedTables() > 0; 645 } 646 647 public List<Table> getImportedTablesAsList() { 648 LinkedHashSet<Table> tables = Sets.newLinkedHashSet(Lists.transform(this.importedKeys, new Function<Column,Table>(){ 649 @Override 650 public Table apply(Column t) { 651 return t.getTable(); 652 }})); 653 return Lists.newArrayList(tables); 654 } 655 public Table[] getImportedTables() { 656 return getImportedTablesAsList().toArray(new Table[0]); 657 } 658 public int countForeignTables() { 659 return this.getForeignTables().length; 660 } 661 662 public boolean hasForeignTables() { 663 return this.countForeignTables() > 0; 664 } 665 666 public List<Table> getForeignTablesAsList() { 667 LinkedHashSet<Table> tables = Sets.newLinkedHashSet(Lists.transform(this.foreignKeys, new Function<Column,Table>(){ 668 @Override 669 public Table apply(Column t) { 670 return t.getForeignColumn().getTable(); 671 }})); 672 return Lists.newArrayList(tables); 673 } 674 public Table[] getForeignTables() { 675 return getForeignTablesAsList().toArray(new Table[0]); 676 } 677 public Table getRelationTable(Table targetTable) { 678 System.out.println("getRelationTable " + this.getName() + "<->" + targetTable.getName() + ")"); 679 Table[] importedTables = this.getImportedTables(); 680 for (int iIndex = 0; iIndex < importedTables.length; ++iIndex) { 681 Table[] foreignTables = importedTables[iIndex].getForeignTables(); 682 for (int iIndex2 = 0; iIndex2 < foreignTables.length; ++iIndex2) { 683 if (!foreignTables[iIndex2].getName().equalsIgnoreCase(this.getName())) 684 continue; 685 return importedTables[iIndex]; 686 } 687 } 688 return targetTable; 689 } 690 691 public int countProcedures() { 692 return this.procedures.size(); 693 } 694 695 public boolean hasProcedures() { 696 return this.countProcedures() > 0; 697 } 698 699 public Procedure[] getProcedures() { 700 return this.procedures.toArray( new Procedure[this.procedures.size()]); 701 } 702 703 public void addProcedure(Procedure procedure) { 704 if (null == this.procHash.get(procedure.getName())) { 705 this.procedures.add(procedure); 706 this.procHash.put(procedure.getName(), procedure); 707 } 708 } 709 710 public String[] getLinkedPackages() { 711 Vector<String> vector = new Vector<String>(); 712 Table[] linkedTables = this.getLinkedTables(); 713 for (int iIndex = 0; iIndex < linkedTables.length; ++iIndex) { 714 if (vector.contains(linkedTables[iIndex].getPackage())) 715 continue; 716 vector.add(linkedTables[iIndex].getPackage()); 717 } 718 return vector.toArray(new String[vector.size()]); 719 } 720 721 public String getPackage() { 722 String basePackage = CodeWriter.getProperty((String) "codewriter.package"); 723 return checkNotNull(basePackage,"NOT DEFINED codewriter.package"); 724 } 725 726 public String getPackagePath() { 727 return this.getPackage().replace('.', '/') + "/"; 728 } 729 730 public Column getFirstColumn() { 731 return (Column) this.cols.get(0); 732 } 733 734 public String getRemarks() { 735 return this.remarks == null ? "" : this.remarks; 736 } 737 738 public boolean hasRemarks(){ 739 return !getRemarks().isEmpty(); 740 } 741 public String getJavaName() { 742 return this.convertName(""); 743 } 744 745 public String getBasename(Boolean nsp){ 746 String basename =Boolean.TRUE == nsp 747 ? this.getName().replaceFirst(this.getDatabase().getSamePrefix(), "") 748 : this.getName(); 749 return "".equals(CodeWriter.getClassPrefix()) 750 ? basename 751 : CodeWriter.getClassPrefix() + "_" + basename; 752 } 753 754 public String convertName(String value,Boolean nsp) { 755 String basename = getBasename(nsp); 756 if ("".equals(value)) { 757 return StringUtilities.convertName((String) basename, false); 758 } 759 return StringUtilities.convertName((String) (basename + "_" + value), false); 760 } 761 762 public String convertName(String value) { 763 return convertName(value,false); 764 } 765 766 public String convertNameNSP(String value) { 767 return convertName(value,true); 768 } 769 770 public String asClass(String suffix) { 771 return this.convertName(suffix); 772 } 773 774 public String asCoreClass() { 775 return this.convertName(""); 776 } 777 778 public String asCoreClassNSP() { 779 return this.convertNameNSP(""); 780 } 781 public String asCoreClass(Boolean nsp) { 782 return this.convertName("",nsp); 783 } 784 public String asBeanClass() { 785 return this.convertName("Bean"); 786 } 787 788 public String asFullBeanClass() { 789 return this.getPackage() + "." + this.asBeanClass(); 790 } 791 792 public String asBeanClassNSP() { 793 return this.convertNameNSP("Bean"); 794 } 795 796 public String asBeanClass(Boolean nsp) { 797 return convertName("Bean",nsp); 798 } 799 public String asConstClass() { 800 return this.convertName("Const"); 801 } 802 public String asConstClass(boolean nsp) { 803 return this.convertName("Const",nsp); 804 } 805 public String asConstClassNSP() { 806 return asConstClass(true); 807 } 808 public String asCacheClass() { 809 return this.convertName("Cache"); 810 } 811 public String asCacheClass(boolean nsp) { 812 return this.convertName("Cache",nsp); 813 } 814 public String asRelationnalBeanClass() { 815 return this.convertName("Relationnal_Bean"); 816 } 817 818 public String asHibernateManagerClass() { 819 return this.convertName("Hibernate_Manager"); 820 } 821 822 public String asIteratorClass() { 823 return this.convertName("Iterator"); 824 } 825 826 public String asFactoryClass() { 827 return this.convertName("Factory"); 828 } 829 830 public String asHttpFactoryClass() { 831 return this.convertName("Http_Factory"); 832 } 833 834 public String asComparatorClass() { 835 return this.convertName("Comparator"); 836 } 837 838 public String asComparatorClass(Boolean nsp) { 839 return convertName("Comparator",nsp); 840 } 841 public String asListenerClass() { 842 return this.convertName("Listener"); 843 } 844 845 public String asListenerClassNSP() { 846 return this.convertNameNSP("Listener"); 847 } 848 849 public String asRendererClass() { 850 return this.convertName("Renderer"); 851 } 852 853 public String asExceptionClass() { 854 return this.convertName("Exception"); 855 } 856 857 public String asWidgetClass() { 858 return this.convertName("Widget"); 859 } 860 861 public String asWidgetFactoryClass() { 862 return this.convertName("Widget_Factory"); 863 } 864 865 public String asActionClass() { 866 return this.convertName("Action"); 867 } 868 869 public String asActionTestClass() { 870 return this.convertName("Action_Test"); 871 } 872 873 public String asControllerClass() { 874 return this.convertName("Controller"); 875 } 876 877 public String asControllerTestClass() { 878 return this.convertName("Controller_Test"); 879 } 880 881 public String asFormControllerClass() { 882 return this.convertName("Form_Controller"); 883 } 884 885 public String asFormControllerTestClass() { 886 return this.convertName("Form_Controller_Test"); 887 } 888 889 public String asDAOClass() { 890 return this.convertName("D_A_O"); 891 } 892 893 public String asDAOTestClass() { 894 return this.convertName("D_A_O_Test"); 895 } 896 897 public String asDAOHibernateClass() { 898 return this.convertName("D_A_O_Hibernate"); 899 } 900 901 public String asManagerClass() { 902 return this.convertName("Manager"); 903 } 904 public String asManagerClass(Boolean nsp) { 905 return this.convertName("Manager",nsp); 906 } 907 public String asManagerClassNSP() { 908 return this.convertNameNSP("Manager"); 909 } 910 public String asManagerInterfaceNSP() { 911 return "I"+asManagerClassNSP(); 912 } 913 public String asManagerImplClass() { 914 return this.convertName("Manager_Impl"); 915 } 916 public String asMetaDataClassNSP() { 917 return asCoreClass(true) + "MetaData"; 918 } 919 public String asManagerTestClass() { 920 return this.convertName("Manager_Test"); 921 } 922 public String asCacheManagerClass() { 923 return this.convertName("cache_manager"); 924 } 925 public String asCacheManagerClassNSP() { 926 return this.convertNameNSP("cache_manager"); 927 } 928 public String asCacheManagerClass(boolean nsp) { 929 return this.convertName("cache_manager",nsp); 930 } 931 public String asVar(String prefix,String suffix){ 932 return StringUtilities.convertName( prefix + getBasename(true) + suffix,true); 933 } 934 public String asVar(String prefix){ 935 return asVar(prefix,""); 936 } 937 public String asVar(){ 938 return asVar("",""); 939 } 940 public String asVarBean(){ 941 return asVar("","_Bean"); 942 } 943 public String asVarManager(){ 944 return asVar("","_Manager"); 945 } 946 public String asConverterVar(){ 947 return "converter" + asBeanClassNSP() ; 948 } 949 public String asConverterConstVar(){ 950 return "converter_".concat(asBeanClassNSP()).toUpperCase(); 951 } 952 public String asCacheVarName(){ 953 return StringUtilities.convertName( getBasename(true) + "_cache",true); 954 } 955 public String asCacheVarSetMethod(){ 956 return StringUtilities.convertName("set_" + getBasename(true) + "_cache",true); 957 } 958 public String asCacheVarGetMethod(){ 959 return StringUtilities.convertName("get_" + getBasename(true) + "_cache",true); 960 } 961 public String asInstanceMethod(Boolean nsp){ 962 return "instanceOf" + asManagerClass(nsp); 963 } 964 public String asModelClass() { 965 return this.convertName("Model"); 966 } 967 968 public String asPKClass() { 969 return this.convertName("P_K"); 970 } 971 972 public String asTblClass() { 973 return this.convertName("Tbl"); 974 } 975 976 public Column getVersionColumn() { 977 int nbCols = this.cols.size(); 978 for (int i = 0; i < nbCols; ++i) { 979 Column c = (Column) this.cols.get(i); 980 if (!c.isVersion()) 981 continue; 982 return c; 983 } 984 throw new IllegalArgumentException("No version column for table " + this.getName()); 985 } 986 987 public boolean hasVersionColumn() { 988 try { 989 this.getVersionColumn(); 990 return true; 991 } catch (IllegalArgumentException e) { 992 return false; 993 } 994 } 995 996 public long getSerialVersionUID() { 997 return this.aleatorio.nextLong(); 998 } 999 /** 1000 * 生成MD5校验码 1001 * 1002 * @param source 1003 * @return 1004 */ 1005 static public byte[] getMD5(byte[] source) { 1006 if (null==source) 1007 return null; 1008 try { 1009 MessageDigest md = MessageDigest.getInstance("MD5"); 1010 return md.digest(source); 1011 } catch (NoSuchAlgorithmException e) { 1012 throw new RuntimeException(e); 1013 } 1014 } 1015 /** 1016 * 将字节数组转为long<br> 1017 * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常 1018 * @param input 1019 * @param offset 起始偏移量 1020 * @param littleEndian 输入数组是否小端模式 1021 * @return 1022 */ 1023 public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){ 1024 if(offset <0 || offset+8>input.length) 1025 throw new IllegalArgumentException(String.format("less than 8 bytes from index %d is insufficient for long",offset)); 1026 long value=0; 1027 for(int count=0;count<8;++count){ 1028 int shift=(littleEndian?count:(7-count))<<3; 1029 value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); 1030 } 1031 return value; 1032 } 1033 /** 1034 * 根据输入的String返回唯一的UID(long) 1035 * @param input 1036 * @return 1037 */ 1038 public long getSerialVersionUID(String input){ 1039 byte[] md5 = getMD5(input.getBytes()); 1040 return longFrom8Bytes(md5,0, false) ^ longFrom8Bytes(md5,8, false); 1041 } 1042 public String asFkVar(String fkName){ 1043 return StringUtilities.convertName(toUniversalFkName(fkName),true); 1044 } 1045 public String asIKVar(String fkName){ 1046 Table foreignTable = this.getForeignTableByFkName(fkName); 1047 return null==foreignTable 1048 ? "" 1049 : StringUtilities.convertName(toUniversalFkName(fkName) + "_of_" +getBasename(true), true); 1050 } 1051 1052 public String asFKConst(String fkName){ 1053 return (this.name+"_FK_" + toUniversalFkName(fkName)).toUpperCase(); 1054 } 1055 1056 public String asIKConst(String fkName){ 1057 Table foreignTable = this.getForeignTableByFkName(fkName); 1058 return (null==foreignTable?"":foreignTable.getName() + "_IK_" + this.name +"_" + toUniversalFkName(fkName)).toUpperCase(); 1059 } 1060 1061 public String asRefArg(String fkName){ 1062 return StringUtilities.convertName("ref_"+ this.getForeignTableByFkName(fkName).asCoreClassNSP() +"_by_" + toUniversalFkName(fkName),true); 1063 } 1064 1065 public String asImpArg(String fkName){ 1066 return StringUtilities.convertName("imp_"+ this.asCoreClassNSP() +"_by_" + toUniversalFkName(fkName),true); 1067 } 1068 1069 public String getReferencedVarName(String fkName){ 1070 return StringUtilities.convertName("referenced_by_" + toUniversalFkName(fkName),true); 1071 } 1072 1073 public String getReferencedVarGetMethod(String fkName) { 1074 return StringUtilities.convertName("get_" + "referenced_by_" + toUniversalFkName(fkName),true); 1075 } 1076 1077 public String getReferencedVarSetMethod(String fkName){ 1078 return StringUtilities.convertName("set_" + "referenced_by_" + toUniversalFkName(fkName),true); 1079 } 1080 1081 public String getImportedBeansGetMethod(String fkName) { 1082 return "get" + this.asBeanClassNSP() + "s" + StringUtilities.convertName("By_" + toUniversalFkName(fkName),false); 1083 } 1084 public String getImportedBeansSetMethod(String fkName) { 1085 return "set" + this.asBeanClassNSP() + "s" + StringUtilities.convertName("By_" + toUniversalFkName(fkName),false); 1086 } 1087 public String getImportedBeansDelMethod(String fkName) { 1088 return "delete" + this.asBeanClassNSP() + "s" + StringUtilities.convertName("By_" + toUniversalFkName(fkName),false); 1089 } 1090 1091 public String getForeignKeyListenerVar(String fkName) { 1092 return "foreignKeyListener" + StringUtilities.convertName("By_" + toUniversalFkName(fkName),false); 1093 } 1094 public String getBindMethod(String fkName) { 1095 return StringUtilities.convertName( 1096 Joiner.on('_').join("bind", 1097 toUniversalFkName(fkName),"listener", 1098 "to", 1099 getForeignTableByFkName(fkName).getBasename(false),"Manager"), 1100 true); 1101 } 1102 public boolean stateVarTypeIsArray(){ 1103 return countColumns()>CodeWriter.getBitStateClassSize(); 1104 } 1105 public String stateVarType(){ 1106 return stateVarTypeIsArray() ? CodeWriter.getBitStateClassName() + "[]" : CodeWriter.getBitStateClassName(); 1107 } 1108 /** 生成全0L的modified初始值 */ 1109 public String maskInitializeWithZero(){ 1110 if(stateVarTypeIsArray()){ 1111 int len = (countColumns() + CodeWriter.getBitStateClassSize() - 1)/CodeWriter.getBitStateClassSize(); 1112 StringBuffer sb = new StringBuffer(); 1113 for(int i=0;i<len;++i){ 1114 if(i>0)sb.append(","); 1115 sb.append("0" + CodeWriter.getBitStateConstSuffix()); 1116 } 1117 return String.format("new " + CodeWriter.getBitStateClassName() + "[]{%s}",sb.toString()); 1118 }else{ 1119 return "0" + CodeWriter.getBitStateConstSuffix(); 1120 } 1121 } 1122 1123 /** 根据字段是否有default value生成initialized字段初始值 */ 1124 public String maskInitializeWithDefaultValue(){ 1125 if(stateVarTypeIsArray()){ 1126 final long[] array = new long[(countColumns()+CodeWriter.getBitStateClassSize() - 1)/CodeWriter.getBitStateClassSize()]; 1127 Arrays.fill(array, 0L); 1128 Collections2.filter(getColumnsAsList(), new Predicate<Column>(){ 1129 @Override 1130 public boolean apply(Column input) { 1131 if(!input.getDefaultValue().isEmpty()){ 1132 int index = input.getOrdinalPosition()-1; 1133 array[index/CodeWriter.getBitStateClassSize()] |= (1L << (index & CodeWriter.getBitStateMask())); 1134 } 1135 return false; 1136 }}); 1137 String initValue = Joiner.on(',').join(Lists.transform(Longs.asList(array),new Function<Long,String>(){ 1138 @Override 1139 public String apply(Long input) { 1140 return "0B" + Long.toBinaryString(input.longValue()) + CodeWriter.getBitStateConstSuffix(); 1141 }})); 1142 return String.format("new " + CodeWriter.getBitStateClassName() + "[]{%s}",initValue); 1143 }else{ 1144 Collection<Column> defCols = Collections2.filter(getColumnsAsList(), new Predicate<Column>(){ 1145 @Override 1146 public boolean apply(Column input) { 1147 return !input.getDefaultValue().isEmpty(); 1148 }}); 1149 String mask = Joiner.on(" | ").join(Collections2.transform(defCols, 1150 new Function<Column,String>(){ 1151 @Override 1152 public String apply(Column input) { 1153 return input.getIDMaskConstName(); 1154 }})); 1155 return mask.isEmpty()?"0" + CodeWriter.getBitStateConstSuffix():"("+mask+")"; 1156 } 1157 } 1158 1159 public String stateVarAssignStatement(String src,String dst){ 1160 if(stateVarTypeIsArray()){ 1161 return "if( null != ${src} && ${dst}.length != ${src}.length )System.arraycopy(${src},0,${dst},0,${dst}.length)" 1162 .replace("${src}", src).replace("${dst}", dst); 1163 }else{ 1164 return dst + " = " + src; 1165 } 1166 } 1167 public String getLoadMethodOfJunction(){ 1168 if(this.isJunctionTable()){ 1169 return "load" + "Via" + this.asCoreClass(true); 1170 } 1171 return ""; 1172 } 1173 protected Database getDatabase() { 1174 return database; 1175 } 1176 1177 protected void setDatabase(Database database) { 1178 this.database = database; 1179 } 1180 1181 public Column getAutoincrement() { 1182 return autoincrement; 1183 } 1184 1185 public void setAutoincrement(Column autoincrement) { 1186 this.autoincrement = autoincrement; 1187 } 1188 1189 public int countForeignKeyNames(){ 1190 return this.getFkMapNames().size(); 1191 } 1192 1193 public int countImportedKeyNames(){ 1194 int count = 0; 1195 for(Table table:this.getImportedTables()){ 1196 count += table.getFkMapNames(this.getName()).size(); 1197 } 1198 return count; 1199 } 1200 public String bitResetAssignExpression(Column[]columns,String varName,String indent){ 1201 if(null == columns || 0 == columns.length)return "// columns is null or empty"; 1202 if(null == indent)indent = ""; 1203 if(stateVarTypeIsArray()){ 1204 StringBuffer buffer = new StringBuffer(); 1205 for(Column column : columns){ 1206 int pos = column.getOrdinalPosition()-1; 1207 buffer.append(indent).append(String.format("%s[%d] &= (~(1L << %d));\n",varName,pos>>6,pos & 0x3f)); 1208 } 1209 return buffer.toString(); 1210 }else{ 1211 StringBuffer buffer = new StringBuffer("("); 1212 for(int i=0;i<columns.length;++i){ 1213 if(i > 0) 1214 buffer.append(" |\n").append(indent); 1215 buffer.append(columns[i].getIDMaskConstName()); 1216 } 1217 buffer.append(")"); 1218 return String.format("%s &= (~%s)", varName,buffer.toString()); 1219 } 1220 } 1221 /** 1222 * 包含foreign key信息的数据对象 1223 * @author guyadong 1224 * 1225 */ 1226 public static class ForeignKey{ 1227 /** foreign key name */ 1228 final String fkName; 1229 /** columns of foreign key ,in KEY_SEQ order*/ 1230 final Vector<Column> columns = new Vector<Column>(); 1231 /** UPDATE_RULE */ 1232 final Table.ForeignKeyRule updateRule; 1233 /** DELETE_RULE */ 1234 final Table.ForeignKeyRule deleteRule; 1235 public ForeignKey(String fkName, 1236 Table.ForeignKeyRule updateRule, 1237 Table.ForeignKeyRule deleteRule, 1238 Column columns) { 1239 checkArgument(!Strings.isNullOrEmpty(fkName)); 1240 checkNotNull(columns); 1241 this.fkName = fkName; 1242 this.columns.add(columns); 1243 this.updateRule = checkNotNull(updateRule); 1244 this.deleteRule = checkNotNull(deleteRule); 1245 } 1246 public Table getForeignTable(){ 1247 return columns.get(0).getForeignColumn().getTable(); 1248 } 1249 public Table getTable(){ 1250 return columns.get(0).getTable(); 1251 } 1252 /** 返回主键{@code primaryColumn}对应的字段 */ 1253 public Column foreignColumnOf(Column primaryColumn){ 1254 for(Column column:columns){ 1255 if(column.getForeignColumn().equals(primaryColumn))return column; 1256 } 1257 return null; 1258 } 1259 @Override 1260 public boolean equals(Object obj) { 1261 if(super.equals(obj))return true; 1262 if(!(obj instanceof ForeignKey))return false; 1263 ForeignKey other = (ForeignKey)obj; 1264 return new EqualsBuilder() 1265 .append(fkName, other.fkName) 1266 .append(columns, other.columns) 1267 .append(updateRule, other.updateRule) 1268 .append(deleteRule, other.deleteRule) 1269 .isEquals(); 1270 } 1271 @Override 1272 public String toString() { 1273 return new ToStringBuilder(this) 1274 .append("fkName",fkName) 1275 .append("columns", columns) 1276 .append("updateRule", updateRule) 1277 .append("deleteRule", deleteRule) 1278 .toString(); 1279 } 1280 @Override 1281 public int hashCode() { 1282 return new HashCodeBuilder() 1283 .append(fkName) 1284 .append(columns) 1285 .append(updateRule) 1286 .append(deleteRule) 1287 .toHashCode(); 1288 } 1289 public String getFkName() { 1290 return fkName; 1291 } 1292 public Vector<Column> getColumns() { 1293 return columns; 1294 } 1295 public Table.ForeignKeyRule getUpdateRule() { 1296 return updateRule; 1297 } 1298 public Table.ForeignKeyRule getDeleteRule() { 1299 return deleteRule; 1300 } 1301 public String asFkVar(){ 1302 return StringUtilities.convertName(getUniversalName(),true); 1303 } 1304 public String asIkVar(){ 1305 return StringUtilities.convertName(getUniversalName() + "_of_" +getTable().getBasename(true), true); 1306 } 1307 public String getUniversalName() { 1308 return Joiner.on('_').join(Lists.transform( 1309 columns, 1310 new Function<Column,String>(){ 1311 @Override 1312 public String apply(Column input) { 1313 return input.getName(); 1314 }})); 1315 } 1316 } 1317 public static enum ForeignKeyRule{ 1318 CASCADE("DELETE"),RESTRICT,SET_NULL("UPDATE"),NO_ACTION,SET_DEFAULT("UPDATE"); 1319 private final String eventOfDeleteRule; 1320 1321 private ForeignKeyRule(){ 1322 this(""); 1323 } 1324 private ForeignKeyRule(String event) { 1325 this.eventOfDeleteRule = event; 1326 } 1327 public boolean isNoAction(){ 1328 return this == NO_ACTION || this == RESTRICT; 1329 } 1330 public boolean equals(String value){ 1331 try{ 1332 if(Strings.isNullOrEmpty(value))return false; 1333 return this == ForeignKeyRule.valueOf(value.toUpperCase()); 1334 }catch(Exception e){ 1335 return false; 1336 } 1337 } 1338 public String getEventOfDeleteRule() { 1339 return eventOfDeleteRule; 1340 } 1341 } 1342 public String getCyeleTestMethod(ForeignKey fk) { 1343 return getSelftMethod(fk,"is_cycle_on_"); 1344 } 1345 public String getTopMethod(ForeignKey fk) { 1346 return getSelftMethod(fk,"top_of_"); 1347 } 1348 public String getLevelMethod(ForeignKey fk) { 1349 return getSelftMethod(fk,"level_of_"); 1350 } 1351 public String getListMethod(ForeignKey fk) { 1352 return getSelftMethod(fk,"list_of_"); 1353 } 1354 public String getCheckNotCycleMethod(ForeignKey fk) { 1355 return getSelftMethod(fk,"check_cycle_of_"); 1356 } 1357 public String getChildListMethod(ForeignKey fk) { 1358 return getSelftMethod(fk,"child_list_by_"); 1359 } 1360 private String getSelftMethod(ForeignKey fk,String prefix) { 1361 if(null == fk )return null; 1362 return StringUtilities.convertName( 1363 prefix + getSelfFkSuffix(fk), 1364 true); 1365 } 1366 public String getSelfFkSuffix(ForeignKey fk) { 1367 if(null == fk )return null; 1368 return 1369 Joiner.on('_').join(Lists.transform(fk.columns, new Function<Column,String>(){ 1370 @Override 1371 public String apply(Column input) { 1372 return input.getName(); 1373 }})); 1374 } 1375 public String getGetManagerMethod(){ 1376 return "get" + asManagerClassNSP(); 1377 } 1378}