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