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