1 22 23 28 29 package org.xquark.mapper.metadata; 30 31 import java.sql.*; 32 import java.util.*; 33 34 import org.xml.sax.SAXException ; 35 import org.xquark.mapper.RepositoryException; 36 import org.xquark.mapper.dbms.*; 37 import org.xquark.mapper.mapping.*; 38 import org.xquark.mapper.storage.*; 39 import org.xquark.schema.SchemaComponent; 40 import org.xquark.xml.xdbc.XMLDBCException; 41 import org.xquark.xpath.XTreeRuntimeException; 42 43 48 public class CollectionMetadata implements RepositoryConstants, _Collection 49 { 50 private static final String RCSRevision = "$Revision: 1.4 $"; 51 private static final String RCSName = "$Name: $"; 52 53 54 protected String name; protected short cid; 59 protected CollectionInfo config; protected Repository rep; 61 62 64 protected UOIDManager uoidManager; 65 private PathSetFactory pathSetFactory; 66 67 private PathSet pathSet; 68 private RepositoryMapping mapping; 69 70 private DefaultTableMapping defaultMapping; 71 private List defaultMappingCollection; 72 73 private CollectionMappingInfo[] mappingStatements; 74 75 private int defaultMappingIndex; 76 77 private String selectDocIDStmt; 81 private String renameDocStmt; 82 private String countDocStmt; 83 private String containsDocStmt; 84 private String docListStmt; 85 private String deleteDocIDStmt; 86 87 89 private Map collectionTables; 90 91 94 private short[] tableIndex; 95 96 97 public CollectionMetadata( 98 String name, 99 short cid, 100 CollectionInfo config, 101 Repository rep, 102 MappingFactory mappingFactory 103 ) 104 throws SQLException, XMLDBCException 105 { 106 this.name = name; 108 this.cid = cid; 109 this.rep = rep; 110 this.config = new CollectionInfo(config); 111 this.mapping = (RepositoryMapping)mappingFactory.getTree(); 112 collectionTables = loadTableInfo(cid, rep.getInfo().getColIDSize(), config, getMetadataConnection()); 113 initStatements(); uoidManager = new UOIDManager(this); 115 116 initMapping(mapping, getMetadataConnection()); pathSetFactory = new PathSetFactory(this, mappingFactory); 118 119 AbstractConnection metaConn = getMetadataConnection(); 120 synchronized(metaConn) 121 { 122 metaConn.start(); try { 124 this.pathSet = (PathSet)pathSetFactory.createTree(); } 126 catch (XTreeRuntimeException e) { metaConn.rollback(); 128 if (e.getException() instanceof RepositoryException) 129 throw (RepositoryException)e.getException(); 130 else if (e.getException() instanceof SQLException) 131 throw (SQLException)e.getException(); 132 else 133 throw e; 134 } 135 metaConn.commit(); } 137 initMappingStatements(); } 139 140 private void initMapping(RepositoryMapping mapping, AbstractConnection metadataConn) 141 throws SQLException, XMLDBCException 142 { 143 try 144 { 145 defaultMapping = new DefaultTableMapping(this, metadataConn); 158 defaultMappingIndex = mapping.getTableCount(); 159 defaultMapping.setIndex(defaultMappingIndex); 160 } 161 catch (SAXException e) 162 { 163 throw new RuntimeException ( 164 "Error while creating default table mapping:" + e.getMessage()); 165 } 166 167 int mappingCount = mapping.getTableCount(); 168 mappingStatements = new CollectionMappingInfo[mappingCount + 1]; 169 tableIndex = new short[mappingCount + 1]; 170 for (int i = 0; i < mappingCount; i++) 171 mappingStatements[i] = new CollectionMappingInfo(mapping.getTableMapping(i)); 172 173 mappingStatements[defaultMappingIndex] = new CollectionMappingInfo(defaultMapping); 175 defaultMappingCollection = Collections.singletonList(defaultMapping); 176 } 177 178 private void initMappingStatements() throws XMLDBCException 179 { 180 TableMapping wTable; 181 for (int i = 0; i < mappingStatements.length - 1; i++) 182 { 183 wTable = mappingStatements[i].getTableMapping(); 184 mappingStatements[i].initializeStatements( 185 this, 186 rep.getTableManager().getTableID(wTable.getTableName()), 187 tableIndex[i]); 188 } 189 mappingStatements[defaultMappingIndex].initializeStatements( 190 this, 191 (short)-1, 192 (short)0); 193 } 194 195 private void initStatements() 196 { 197 TableInfo docsTableTable = getTableInfo(TableSpec.TYPE_DOCS); 199 ColumnInfo[] columns = docsTableTable.getColumns(); 200 201 StringBuffer sql = new StringBuffer (); 202 sql.append("SELECT "); 203 sql.append(columns[1].getName()); 204 sql.append(" FROM "); 205 sql.append(docsTableTable.getName()); 206 sql.append(" WHERE "); 207 sql.append(columns[0].getName()); 208 sql.append("='"); 209 selectDocIDStmt = sql.toString(); 210 211 sql.setLength(0); 212 sql.append("UPDATE "); 213 sql.append(docsTableTable.getName()); 214 sql.append(" SET "); 215 sql.append(columns[0].getName()); 216 sql.append("=? WHERE "); 217 sql.append(columns[0].getName()); 218 sql.append("=?"); 219 renameDocStmt = sql.toString(); 220 221 sql.setLength(0); 222 sql.append("SELECT COUNT(*) FROM "); 223 sql.append(docsTableTable.getName()); 224 countDocStmt = sql.toString(); 225 226 sql.setLength(0); 227 sql.append(countDocStmt); 228 sql.append(" WHERE "); 229 sql.append(columns[0].getName()); 230 sql.append("='"); 231 containsDocStmt = sql.toString(); 232 233 sql.setLength(0); 234 sql.append("SELECT "); 235 sql.append(columns[0].getName()); 236 sql.append(" FROM "); 237 sql.append(docsTableTable.getName()); 238 docListStmt = sql.toString(); 239 240 sql.setLength(0); 241 sql.append("DELETE FROM "); 242 sql.append(docsTableTable.getName()); 243 sql.append(" WHERE "); 244 sql.append(columns[0].getName()); 245 sql.append("=?"); 246 deleteDocIDStmt = sql.toString(); 247 } 248 249 public void registerMapping(TableMapping tm, PathNode node) 250 { 251 tableIndex[tm.getTableIndex()] = node.getPathID(); 252 } 253 254 public short getMappingPID(int tableMappingIndex) 255 { 256 return tableIndex[tableMappingIndex]; 257 } 258 259 public AbstractConnection getMetadataConnection() 263 { 264 return rep.getMetadataConnection(); 265 } 266 267 PathSetFactory getPathSetFactory() 268 { 269 return pathSetFactory; 270 } 271 272 public Map getTableInfoMap() 273 { 274 return collectionTables; 275 } 276 277 public String getSelectDocIDStmt() 278 { 279 return selectDocIDStmt; 280 } 281 282 public String getRenameDocStmt() 283 { 284 return renameDocStmt; 285 } 286 287 public String getCountDocStmt() 288 { 289 return countDocStmt; 290 } 291 292 public String getContainsDocStmt() 293 { 294 return containsDocStmt; 295 } 296 297 public String getDocListStmt() 298 { 299 return docListStmt; 300 } 301 302 public String getDeleteDocIDStmt() 303 { 304 return deleteDocIDStmt; 305 } 306 307 public ColumnMapping createDefaultMappingView(SchemaComponent comp) 308 throws RepositoryException 309 { 310 return defaultMapping.createDefaultMappingView( 311 comp, getMetadataConnection().useStringDelimitor()); 312 } 313 314 public int getDefaultMappingIndex() { return defaultMappingIndex;} 315 316 320 public List getDefaultMappingList() 321 { 322 return defaultMappingCollection; 323 } 324 325 public DefaultTableMapping getDefaultMapping() 326 { 327 return defaultMapping; 328 } 329 330 336 public void setName(String newName) { this.name = newName;} 337 338 342 public String getCollectionName() { return name;} 343 344 public short getCollectionID() { return cid;} 345 346 349 public Repository getRepository() { return rep;} 350 351 354 public CollectionInfo getInfo() { return config;} 355 356 public UOIDManager getUOIDManager() { return uoidManager;} 357 358 362 public void close() throws RepositoryException 363 { 364 uoidManager.close(); 365 uoidManager = null; 366 pathSet.close(); 367 pathSet = null; 368 name = null; 369 rep = null; 370 } 371 372 377 public PathSet getPathSet() { return pathSet;} 378 379 public RepositoryMapping getMapping() 380 { 381 return mapping; 382 } 383 384 390 public String getOIDTableName(int tableMappingIndex) throws XMLDBCException 391 { 392 return mappingStatements[tableMappingIndex].getOIDTableName(); 393 } 394 395 private static Map loadTableInfo(short cid, short cidSize, CollectionInfo info, AbstractConnection conn) 396 throws RepositoryException 397 { 398 HashMap map = new HashMap(); 399 400 401 List tables = TableSpecLoader.getInstance().getTableSpecs(TableSpec.CAT_COLLECTION); 402 Iterator it = tables.iterator(); 403 TableSpec wSpec = null; 404 405 long[] params = new long[TableInfo.PARAM_NUMBER]; 406 params[TableInfo.PARAM_DATA_SIZE] = info.getMaxTextLength(); 407 params[TableInfo.PARAM_EXTRA_SIZE] = info.getMaxExtraDataLength(); 408 params[TableInfo.PARAM_DID_SIZE] = info.getDocOIDSize(); params[TableInfo.PARAM_UDID_SIZE] = cidSize + info.getDocOIDSize(); params[TableInfo.PARAM_BID_SIZE] = params[TableInfo.PARAM_UDID_SIZE]; 412 while (it.hasNext()) 413 { 414 wSpec = (TableSpec)it.next(); 415 map.put(new Byte (wSpec.getType()), new TableInfo(wSpec, cid, params, conn)); 416 } 417 return map; 418 } 419 420 public TableInfo getTableInfo(byte type) 421 { 422 return (TableInfo)collectionTables.get(new Byte (type)); 423 } 424 425 public synchronized DocumentInfo getDocumentInfo(String docID) 429 throws RepositoryException 430 { 431 PersistentDocumentInfo docRow = null; 432 try 433 { 434 docRow = new PersistentDocumentInfo( 435 getTableInfo(TableSpec.TYPE_DOCS), 436 getMetadataConnection() 437 ); 438 docRow.fetchRow(docID); 439 return docRow.getDocumentInfo(); 440 } 441 catch (SQLException e) 442 { 443 throw new RepositoryException(RepositoryException.DB_ERROR, 444 "SQL exception while getting document information.", e); 445 } 446 finally 447 { 448 if (docRow != null) 449 docRow.close(); 450 } 451 } 452 453 public synchronized List getDocumentInfoList(XMLCollectionImpl collection) throws RepositoryException 454 { 455 PersistentDocumentInfo docRow = null; 456 ArrayList docList = new ArrayList(); 457 try 458 { 459 docRow = new PersistentDocumentInfo( 460 getTableInfo(TableSpec.TYPE_DOCS), 461 getMetadataConnection() 462 ); 463 docRow.retrieveDataSet(); 464 while (docRow.fetchNextRow()) 465 docList.add(new RepositoryDocumentImpl(docRow.getDocumentInfo(), collection)); 466 } 467 catch (SQLException e) 468 { 469 throw new RepositoryException(RepositoryException.DB_ERROR, 470 "SQL exception while getting document information.", e); 471 } 472 finally 473 { 474 if (docRow != null) 475 docRow.close(); 476 } 477 return docList; 478 } 479 480 public synchronized void createIndexes() throws RepositoryException 481 { 482 createIndexes(mapping, config, cid, collectionTables.values(), rep, getMetadataConnection()); 483 } 484 485 public synchronized void dropIndexes() throws RepositoryException 486 { 487 dropIndexes(mapping, config, cid, collectionTables.values(), rep, getMetadataConnection()); 488 } 489 490 491 public synchronized void updateStatistics() throws XMLDBCException 492 { 493 DatabaseMetaData DBMeta = null; 494 ResultSet rs = null; 495 496 try 497 { 498 DBMeta = getMetadataConnection().getConnection().getMetaData(); 500 rs = DBMeta.getTables( 501 null, 502 getMetadataConnection().getSchemaName(), 503 TABLE_PREFIX + name + "%", 504 null 505 ); 506 while (rs.next()) 507 { 508 getMetadataConnection().updateStatistics(rs.getString(3)); 509 } 510 511 int tableCount = mapping.getTableCount(); 513 for (int i = 0; i <tableCount; i++) 514 { 515 getMetadataConnection().updateStatistics(mapping.getTableMapping(i).getTableName()); 516 } 517 } 518 catch (SQLException e) { 519 throw new RepositoryException(RepositoryException.DB_ERROR, 520 "SQL exception while trying to update database statistics", e); 521 } 522 finally 523 { 524 try 525 { 526 if (rs != null) 527 rs.close(); 528 } 529 catch (SQLException e) 530 { 531 } 533 534 } 535 536 } 537 538 540 public synchronized void refresh() throws XMLDBCException 541 { 542 pathSet.refresh(); 543 } 544 545 public void updateDescription(String desc) throws XMLDBCException 546 { 547 try 548 { 549 rep.updateCollectionDescription(cid, desc); 550 } 551 catch (SQLException e) 552 { 553 throw new RepositoryException(RepositoryException.DB_ERROR, 554 "Could not update collection description.", e); 555 } 556 config.setDescription(desc); 557 } 558 559 static void initializeCollection( 563 RepositoryMapping mapping, 564 PersistentCollectionInfo configRow, 565 Repository rep, 566 AbstractConnection connection 567 ) 568 throws RepositoryException 569 { 570 try { 571 572 try 573 { 574 configRow.createRow(); 575 } 576 catch (SQLException e) 577 { 578 throw new RepositoryException(RepositoryException.DB_ERROR, 579 "Failed to insert collection in configuration table.", e); 580 } 581 582 583 Map tableInfo = loadTableInfo 584 ( 585 configRow.getCollectionID(), 586 rep.getInfo().getColIDSize(), 587 configRow.getCollectionInfo(), 588 connection 589 ); 590 591 592 Iterator it = connection.createTables(tableInfo.values()).iterator(); 593 TableInfo wTable; 594 595 596 while (it.hasNext()) 597 { 598 wTable = (TableInfo)it.next(); 599 short step = 1; 600 if (wTable.getType() == TableSpec.TYPE_DOC_SEQ) 601 step = configRow.getCollectionInfo().getDocOIDPreallocationSize(); 602 new Sequence(wTable, step).create(connection); 603 } 604 } 605 catch (SQLException e) 606 { 607 dropCollectionTables(configRow, connection); throw new RepositoryException(RepositoryException.DB_ERROR, 610 "Failed to create tables for collection.", e); 611 } 612 613 Statement stmt = null; 615 try 616 { 617 Iterator it = mapping.joinTableIterator(); 618 TableMapping table; 619 String SQLString; 620 String [] indexes; 621 622 stmt = connection.getConnection().createStatement(); 623 while (it.hasNext()) 624 { 625 table = (TableMapping) it.next(); 626 CollectionMappingInfo generator = 628 new CollectionMappingInfo( 629 table, 630 configRow.getCollectionID(), 631 rep.getTableManager().getTableID(table.getTableName()), 632 connection); 633 connection.addBatch( 634 stmt, 635 generator.getOIDTableCreateStatement()); 636 indexes = generator.getOIDIndexCreateStatements(); 637 638 for (int i = 0; i < indexes.length; i++) 639 connection.addBatch(stmt, indexes[i]); 640 } 641 connection.executeBatch(stmt); 642 643 } 644 catch (SQLException e) 645 { 646 dropCollectionTables(configRow, connection); 649 try 651 { 652 configRow.deleteRow(); 653 } 654 catch (SQLException ex) 655 { 656 throw new RepositoryException(RepositoryException.DB_ERROR, 657 "Failed to create system tables for collection and could no remove entry in collection table.", ex); 658 } 659 660 throw new RepositoryException(RepositoryException.DB_ERROR, 661 "Failed to create system tables for collection.", e); 662 } 663 } 664 665 static void dropCollectionTables(PersistentCollectionInfo configRow, short cidSize, AbstractConnection connection) 666 throws RepositoryException 667 { 668 669 Map tableInfo = loadTableInfo 670 ( 671 configRow.getCollectionID(), 672 cidSize, 673 configRow.getCollectionInfo(), 674 connection 675 ); 676 dropCollectionTables(configRow, connection); 677 } 678 679 private static void dropCollectionTables( 680 PersistentCollectionInfo configRow, 681 AbstractConnection connection 682 ) 683 throws RepositoryException 684 { 685 String pattern = TABLE_PREFIX + configRow.getCollectionID() + "%"; 687 try 688 { 689 Iterator it = connection.getUserTableNames(pattern).iterator(); 690 while (it.hasNext()) 691 { 692 try 693 { 694 connection.dropTable((String )it.next()); 695 } 696 catch (SQLException e) 697 { 698 } 700 } 701 } 702 catch (SQLException e) 703 { 704 throw new RepositoryException(RepositoryException.DB_ERROR, 705 "Failed to drop collection tables.", e); 706 } 707 708 try 710 { 711 Iterator it = connection.getUserSequenceNames(pattern).iterator(); 712 while (it.hasNext()) 713 { 714 try 715 { 716 connection.dropSequence((String )it.next()); 717 } 718 catch (SQLException e) 719 { 720 } 722 } 723 } 724 catch (SQLException e) 725 { 726 throw new RepositoryException(RepositoryException.DB_ERROR, 727 "Failed to drop collection sequences.", e); 728 } 729 } 730 731 735 public static void createIndexes( 736 RepositoryMapping mapping, 737 CollectionInfo config, 738 short cid, 739 Repository rep, 740 AbstractConnection connection 741 ) 742 throws RepositoryException 743 { 744 createIndexes ( 745 mapping, 746 config, 747 cid, 748 loadTableInfo(cid, rep.getInfo().getColIDSize(), config, connection).values(), 749 rep, 750 connection 751 ); 752 753 } 754 755 759 public static void dropIndexes( 760 RepositoryMapping mapping, 761 CollectionInfo config, 762 short cid, 763 Repository rep, 764 AbstractConnection connection 765 ) 766 throws RepositoryException 767 { 768 dropIndexes ( 769 mapping, 770 config, 771 cid, 772 loadTableInfo(cid, rep.getInfo().getColIDSize(), config, connection).values(), 773 rep, 774 connection 775 ); 776 777 } 778 779 void releaseJDBCRessources() 783 { 784 pathSet.releaseJDBCRessources(); 785 } 786 787 791 private static void createIndexes( 792 RepositoryMapping mapping, 793 CollectionInfo config, 794 short cid, 795 Collection tableInfos, 796 Repository rep, 797 AbstractConnection connection 798 ) 799 throws RepositoryException 800 { 801 802 try { 803 connection.createIndexes(tableInfos); 804 } 805 catch(SQLException e) 806 { 807 throw new RepositoryException(RepositoryException.DB_ERROR, 808 "JDBC error while creating indexes on collection tables.", e); 809 } 810 811 Statement stmt = null; 812 try { 813 Iterator it = mapping.joinTableIterator(); 815 String [] SQLStmts; 816 TableMapping table = null; 817 818 stmt = connection.getConnection().createStatement(); 819 while (it.hasNext()) 820 { 821 table = (TableMapping) it.next(); 822 CollectionMappingInfo generator = 824 new CollectionMappingInfo( 825 table, 826 cid, 827 rep.getTableManager().getTableID(table.getTableName()), 828 connection); 829 SQLStmts = generator.getOIDIndexCreateStatements(); 830 for (int i = 0; i < SQLStmts.length; i++) 831 connection.addBatch(stmt, SQLStmts[i]); 832 } 833 connection.executeBatch(stmt); 834 } 835 catch(SQLException e) 836 { 837 throw new RepositoryException(RepositoryException.DB_ERROR, 838 "JDBC error while creating indexes on data index tables.", e); 839 } 840 finally 841 { 842 try 843 { 844 if (stmt != null) 845 stmt.close(); 846 } 847 catch(SQLException ex) 848 { 849 } 851 } 852 } 853 854 private static void dropIndexes( 855 RepositoryMapping mapping, 856 CollectionInfo config, 857 short cid, 858 Collection tableInfos, 859 Repository rep, 860 AbstractConnection connection 861 ) 862 throws RepositoryException 863 { 864 865 try { 866 connection.dropIndexes(tableInfos); 867 } 868 catch(SQLException e) 869 { 870 throw new RepositoryException(RepositoryException.DB_ERROR, 871 "JDBC error while dropping indexes on collection tables.", e); 872 } 873 874 875 Statement stmt = null; 876 try 877 { 878 Iterator it = mapping.joinTableIterator(); 880 String [] SQLStmts; 881 TableMapping table = null; 882 883 stmt = connection.getConnection().createStatement(); 884 while (it.hasNext()) 885 { 886 table = (TableMapping) it.next(); 887 CollectionMappingInfo generator = 889 new CollectionMappingInfo( 890 table, 891 cid, 892 rep.getTableManager().getTableID(table.getTableName()), 893 connection); 894 SQLStmts = generator.getOIDIndexDropStatements(); 895 for (int i = 0; i < SQLStmts.length; i++) 896 connection.addBatch(stmt, SQLStmts[i]); 897 } 898 connection.executeBatch(stmt); 899 } 900 catch(SQLException e) 901 { 902 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while creating indexes on OID tables.", e); 903 } 904 finally 905 { 906 try 907 { 908 if (stmt != null) 909 stmt.close(); 910 } 911 catch(SQLException e) 912 { 913 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while closing statement.", e); 914 } 915 } 916 } 917 918 public MappingSetIterator getMappingSetIterator() 922 { 923 return new MappingSetIteratorImpl(mappingStatements); 924 } 925 926 public MappingInfo getMappingStatements(int index) 927 { 928 return mappingStatements[index]; 929 } 930 931 public int getMappingStatementsCount() 932 { 933 return mappingStatements.length; 934 } 935 936 public MappingSetIterator getSortedTableMappingSetIterator(final boolean mostDependantFirst) 937 { 938 return new MappingSetIterator() 939 { 940 private int next = 0; 941 private MappingSetIterator mappingIterator 942 = mapping.getSortedTableMappingSetIterator(mostDependantFirst); 943 944 public boolean hasNext() 945 { 946 return (next == 0 && !mostDependantFirst) 947 || mappingIterator.hasNext() 948 || (next == (mappingStatements.length - 1) && mostDependantFirst); 949 } 950 951 public MappingInfo next() 952 { 953 MappingInfo ret = null; 954 next++; 955 if (next == 1 && !mostDependantFirst) 956 ret = mappingStatements[defaultMappingIndex]; 957 else if (next == mappingStatements.length && mostDependantFirst) 958 ret = mappingStatements[defaultMappingIndex]; 959 else if (mappingIterator.hasNext()) 960 ret = mappingStatements[mappingIterator.next().getTableMapping().getTableIndex()]; 961 return ret; 962 } 963 964 public boolean isTableFirstOccurence() 965 { 966 return (((next == 1) && !mostDependantFirst) 967 || ((next == mappingStatements.length) && mostDependantFirst)) 968 || mappingIterator.isTableFirstOccurence(); 969 } 970 971 public int getFirstOccurenceTableIndex() 972 { 973 if ((next == 1 && !mostDependantFirst) 974 || (next == mappingStatements.length && mostDependantFirst)) 975 return defaultMappingIndex; 976 else 977 return mappingIterator.getFirstOccurenceTableIndex(); 978 } 979 980 }; 981 } 982 } 983 | Popular Tags |