001/* 002 * $Source: v:/cvsroot/open/projects/WebARTS/ca/bc/webarts/widgets/JDBCAdapter.java,v $ 003 * $Name: $ 004 * $Revision: 567 $ 005 * $Date: 2012-11-03 20:36:02 -0700 (Sat, 03 Nov 2012) $ 006 * $Locker: $ 007 */ 008/* 009 * Copyright (C) 2001 WebARTS Design, North Vancouver Canada 010 * http://www..webarts.bc.ca 011 * 012 * This program is free software; you can redistribute it and/or modify 013 * it under the terms of the GNU General Public License as published by 014 * the Free Software Foundation; either version 2 of the License, or 015 * (at your option) any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public License 023 * along with this program; if not, write to the Free Software 024 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 025 */ 026package ca.bc.webarts.widgets; 027 028 029import java.sql.*; 030import java.util.Enumeration; 031 032import java.util.Vector; 033import javax.swing.event.TableModelEvent; 034import javax.swing.table.AbstractTableModel; 035 036/** 037 * JDBCAdapter is an encapsulation class, transforming the JDBC interface to the 038 * <code>TableModel</code> interface. This class attempts to abstract the details 039 * of the JDBC DB connection and query specifics. It presents all the results to 040 * the user in the form of a Java <code>TableModel</code> by extending/overiding 041 * the <code>AbstractTableModel</code>. This an then be used to as the basis for 042 * a JTable.<BR> 043 * <BR> 044 * <U>example usage</U> <BR> 045 * <code><PRE> 046 * JDBCAdapter jdbcTableAdapter; 047 * private String dbVendorParam = "oracle", // this can be oracle or db2 048 * dbNameParam = "someDB", // this is the name of the DB to hit 049 * dbUsernameParam = "myUsername", // duh 050 * dbPasswordParam = "myPassword, // duh 051 * dbServerParam = "172.118.88.2", // the name or IP address of the server runing the DB 052 * dbPortParam = "1521"; // the port to use for JDBC access (oracle does not have a seperate listening port it uses the main port) 053 * // see the vendor docs for the specific port to access 054 * boolean dbConnected = false; 055 * String sampleQuery = "SELECT * from employee"; 056 * TableSorter dataSorter = new TableSorter(); 057 * Table table; 058 * 059 * try { 060 * jdbcTableAdapter = new JDBCAdapter(dbVendorParam, dbNameParam, dbUsernameParam, dbPasswordParam, dbServerParam, dbPortParam); 061 * dbConnected = true; 062 * } 063 * catch (java.security.AccessControlException ex) { 064 * System.out.println("Security Exception Connecting to " + dbVendorParam +"'s Database." ); 065 * dbConnected = false; 066 * } 067 * // retrieve data from the database 068 * if (jdbcTableAdapter.isDbConnected()) { 069 * System.out.println("Retrieve Raw data from the database"); 070 * jdbcTableAdapter.executeQuery(sampleQuery); 071 * 072 * // now get the table set up. 073 * dataSorter.setModel(jdbcTableAdapter); 074 * table = new JTable(dataSorter); 075 * } 076 *</PRE> </code> 077 * 078 * @author Philip Milne 079 * @author Tom Gutwin 080 * @created October 23, 2001 081 * @version 1.30 09/25/97 082 * @version 1.90 09/06/00 083 * @see javax.swing.table.AbstractTableModel 084 */ 085public class JDBCAdapter extends AbstractTableModel 086{ 087 /** 088 * The JDBC Connection used for queries. 089 */ 090 private Connection connection; 091 /** 092 * Description of the Field 093 */ 094 private Statement statement; 095 /** 096 * Description of the Field 097 */ 098 private String driverName; 099 /** 100 * Description of the Field 101 */ 102 private String JDBCconnectString; 103 /** 104 * Description of the Field 105 */ 106 private String JDBCconnectString2; 107 /** 108 * Description of the Field 109 */ 110 private String dbConnectString; 111 /** 112 * Description of the Field 113 */ 114 private String oracleDriverName = "oracle.jdbc.driver.OracleDriver"; 115 /** 116 * Description of the Field 117 */ 118 private String db2DriverName = "COM.ibm.db2.jdbc.net.DB2Driver"; 119 /** 120 * Description of the Field 121 */ 122 private ResultSet resultSet; 123 /** 124 * Description of the Field 125 */ 126 private String[] columnNames = {}; 127 /** 128 * Description of the Field 129 */ 130 private Vector rows = new Vector(); 131 /** 132 * Description of the Field 133 */ 134 private ResultSetMetaData metaData; 135 /** 136 * Description of the Field 137 */ 138 private String dbVendor; 139 /** 140 * Description of the Field 141 */ 142 private String dbName; 143 /** 144 * Description of the Field 145 */ 146 private String dbUsername; 147 /** 148 * Description of the Field 149 */ 150 private String dbPassword; 151 /** 152 * Description of the Field 153 */ 154 private String dbServer; 155 /** 156 * Description of the Field 157 */ 158 private String dbPort; 159 /** 160 * Description of the Field 161 */ 162 private boolean errorCondition = false; 163 164 165 /** 166 * Main Constructor for the class. It takes all the parameters to get the connection 167 * set up. It also prints error messages for problems that might be encountered 168 * when getting set up. To do the actaual query call the executeQuery method. 169 * 170 * @param dbV DB Vendor 171 * @param dbN DB Name 172 * @param dbU Username 173 * @param dbPass Password 174 * @param dbS The DB Server Name. 175 * @param dbP The JDBC Port on the DB Server 176 */ 177 public JDBCAdapter(String dbV, String dbN, String dbU, String dbPass, String dbS, String dbP) 178 { 179 180 dbVendor = dbV; 181 dbName = dbN; 182 dbUsername = dbU; 183 dbPassword = dbPass; 184 dbServer = dbS; 185 dbPort = dbP; 186 187 if (dbVendor.equals("oracle")) 188 { 189 driverName = oracleDriverName; 190 try 191 { 192 System.out.println("Registering the " + dbVendor + " JDBC Driver."); 193 //DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); 194 Class.forName(driverName); 195 196 /* 197 * Form the database connect string(TNSNAMES entry) as a name-value pair 198 */ 199 dbConnectString = dbServer + ":" + dbPort + ":" + dbName; 200 JDBCconnectString = new String("jdbc:" + dbVendor + ":thin:@" + 201 dbConnectString); 202 JDBCconnectString2 = new String("jdbc:oracle:thin:" + dbUsername + 203 "/" + dbPassword + "@" + dbConnectString); 204 205 System.out.println("Opening db connection: " + JDBCconnectString); 206 207 connection = DriverManager.getConnection(JDBCconnectString, dbUsername, dbPassword); 208 statement = connection.createStatement(); 209 } 210 catch (ClassNotFoundException ex) 211 { 212 System.err.println("Cannot find the database driver classes."); 213 System.err.println(ex); 214 } 215 catch (SQLException ex) 216 { 217 System.err.println("Cannot connect to this database."); 218 System.err.println(ex); 219 ex.printStackTrace(); 220 } 221 /* 222 * catch (java.security.AccessControlException ex) { 223 * System.err.println("Cannot connect to this database-Security Permission Error"); 224 * System.err.println(ex); 225 * } 226 */ 227 } 228 else 229 { 230 if (dbVendor.equals("db2")) 231 { 232 driverName = db2DriverName; 233 /* 234 * Form the database connect string(TNSNAMES entry) as a name-value pair 235 */ 236 dbConnectString = dbServer + ":" + dbPort + "/" + dbName; 237 JDBCconnectString = new String("jdbc:" + dbVendor + "://" + dbConnectString); 238 try 239 { 240 System.out.println("Registering the " + dbVendor + " JDBC Driver."); 241 Class.forName(driverName); 242 System.out.println("Opening db connection: " + JDBCconnectString); 243 System.out.println("With User: " + dbUsername + " : " + dbPassword); 244 245 connection = DriverManager.getConnection(JDBCconnectString, dbUsername, dbPassword); 246 statement = connection.createStatement(); 247 } 248 catch (ClassNotFoundException ex) 249 { 250 System.err.println("Cannot find the database driver classes."); 251 System.err.println(ex); 252 } 253 catch (SQLException ex) 254 { 255 System.err.println("Cannot connect to this database."); 256 System.err.println(ex); 257 } 258 /* 259 * catch (java.security.AccessControlException ex) { 260 * System.err.println("Cannot connect to this database-Security Permission Error"); 261 * System.err.println(ex); 262 * } 263 */ 264 } 265 else 266 { 267 System.out.println("Sorry Unsupported DBVendor <Supports - Oracle or IBM DB2> "); 268 } 269 } 270 271 } 272 273 274 /** 275 * Copy constructor for this class. It takes an existing JDBCAdapter and returns 276 * a new instantiated JDBCAdapter 277 * 278 * @param jdbcAdapter Description of Parameter 279 */ 280 public JDBCAdapter(JDBCAdapter jdbcAdapter) 281 { 282 dbVendor = jdbcAdapter.getdbVendor(); 283 dbName = jdbcAdapter.getdbName(); 284 dbUsername = jdbcAdapter.getdbUsername(); 285 dbPassword = jdbcAdapter.getdbPassword(); 286 dbServer = jdbcAdapter.getdbServer(); 287 dbPort = jdbcAdapter.getdbPort(); 288 289 if (dbVendor.equals("oracle")) 290 { 291 driverName = oracleDriverName; 292 try 293 { 294 System.out.println("Registering the " + dbVendor + " JDBC Driver."); 295 //DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); 296 Class.forName(driverName); 297 298 /* 299 * Form the database connect string(TNSNAMES entry) as a name-value pair 300 */ 301 dbConnectString = dbServer + ":" + dbPort + ":" + dbName; 302 JDBCconnectString = new String("jdbc:" + dbVendor + ":thin:@" + dbConnectString); 303 JDBCconnectString2 = new String("jdbc:oracle:thin:" + dbUsername + "/" + dbPassword + "@" + dbConnectString); 304 305 System.out.println("Opening db connection: " + JDBCconnectString); 306 307 connection = DriverManager.getConnection(JDBCconnectString, dbUsername, dbPassword); 308 statement = connection.createStatement(); 309 } 310 catch (ClassNotFoundException ex) 311 { 312 System.err.println("Cannot find the database driver classes."); 313 System.err.println(ex); 314 } 315 catch (SQLException ex) 316 { 317 System.err.println("Cannot connect to this database."); 318 System.err.println(ex); 319 ex.printStackTrace(); 320 } 321 /* 322 * catch (java.security.AccessControlException ex) { 323 * System.err.println("Cannot connect to this database-Security Permission Error"); 324 * System.err.println(ex); 325 * } 326 */ 327 } 328 else 329 { 330 if (dbVendor.equals("db2")) 331 { 332 driverName = db2DriverName; 333 /* 334 * Form the database connect string(TNSNAMES entry) as a name-value pair 335 */ 336 dbConnectString = dbServer + ":" + dbPort + "/" + dbName; 337 JDBCconnectString = new String("jdbc:" + dbVendor + "://" + dbConnectString); 338 try 339 { 340 System.out.println("Registering the " + dbVendor + " JDBC Driver."); 341 Class.forName(driverName); 342 System.out.println("Opening db connection: " + JDBCconnectString); 343 System.out.println("With User: " + dbUsername + " : " + dbPassword); 344 345 connection = DriverManager.getConnection(JDBCconnectString, dbUsername, dbPassword); 346 statement = connection.createStatement(); 347 } 348 catch (ClassNotFoundException ex) 349 { 350 System.err.println("Cannot find the database driver classes."); 351 System.err.println(ex); 352 } 353 catch (SQLException ex) 354 { 355 System.err.println("Cannot connect to this database."); 356 System.err.println(ex); 357 } 358 /* 359 * catch (java.security.AccessControlException ex) { 360 * System.err.println("Cannot connect to this database-Security Permission Error"); 361 * System.err.println(ex); 362 * } 363 */ 364 } 365 else 366 { 367 System.out.println("Sorry Unsupported DBVendor <Supports - Oracle or IBM DB2> "); 368 } 369 } 370 } 371 372 373 /** 374 * This constructor takes a URL (in the form of a String) as well as the Drivername, 375 * username, password and then creates the Adapter. Thgis allows the constructor 376 * to set up the connection without having to pass the vendor/DB/server info 377 * seperately. 378 * 379 * @param url Description of Parameter 380 * @param driverName Description of Parameter 381 * @param user Description of Parameter 382 * @param passwd Description of Parameter 383 */ 384 public JDBCAdapter(String url, String driverName, 385 String user, String passwd) 386 { 387 try 388 { 389 Class.forName(driverName); 390 System.out.println("Opening db connection"); 391 392 connection = DriverManager.getConnection(url, user, passwd); 393 statement = connection.createStatement(); 394 } 395 catch (ClassNotFoundException ex) 396 { 397 System.err.println("Cannot find the database driver classes."); 398 System.err.println(ex); 399 } 400 catch (SQLException ex) 401 { 402 System.err.println("Cannot connect to this database."); 403 System.err.println(ex); 404 } 405 } 406 407 408 /** 409 * Sets the ErrorCondition attribute of the JDBCAdapter object 410 * 411 * @param val The new ErrorCondition value 412 */ 413 public void setErrorCondition(boolean val) 414 { 415 errorCondition = val; 416 } 417 418 419 /** 420 * Sets the value at the specified cell in the DB to the object supplied. It 421 * will take care of any casting/ type changing required to get it into the speced 422 * column. this method is for the Implementation of the TableModel Interface 423 * 424 * @param value The new ValueAt value 425 * @param row The new ValueAt value 426 * @param column The new ValueAt value 427 */ 428 public void setValueAt(Object value, int row, int column) 429 { 430 try 431 { 432 String tableName = metaData.getTableName(column + 1); 433 // Some of the drivers seem buggy, tableName should not be null. 434 if (tableName == null) 435 { 436 System.out.println("Table name returned null."); 437 } 438 String columnName = getColumnName(column); 439 String query = 440 "update " + tableName + 441 " set " + columnName + " = " + dbRepresentation(column, value) + 442 " where "; 443 // We don't have a model of the schema so we don't know the 444 // primary keys or which columns to lock on. To demonstrate 445 // that editing is possible, we'll just lock on everything. 446 for (int col = 0; col < getColumnCount(); col++) 447 { 448 String colName = getColumnName(col); 449 if (colName.equals("")) 450 { 451 continue; 452 } 453 if (col != 0) 454 { 455 query = query + " and "; 456 } 457 query = query + colName + " = " + 458 dbRepresentation(col, getValueAt(row, col)); 459 } 460 System.out.println(query); 461 System.out.println("Not sending update to database"); 462 // statement.executeQuery(query); 463 } 464 catch (SQLException e) 465 { 466 // e.printStackTrace(); 467 System.err.println("Update failed"); 468 } 469 Vector dataRow = (Vector) rows.elementAt(row); 470 dataRow.setElementAt(value, column); 471 472 } 473 474 475 /** 476 * Gets the ErrorCondition attribute of the JDBCAdapter object 477 * 478 * @return The ErrorCondition value 479 */ 480 public boolean getErrorCondition() 481 { 482 return errorCondition; 483 } 484 485 486 /** 487 * Tells whether there is an active and usable DB connection 488 * 489 * @return boolean flags if there is an active and usable DB connection 490 */ 491 public boolean isDbConnected() 492 { 493 boolean retVal = false; 494 if (connection != null) 495 { 496 retVal = true; 497 } 498 return retVal; 499 } 500 501 502 ////////////////////////////////////////////////////////////////////////// 503 // 504 // Implementation of the TableModel Interface 505 // 506 ////////////////////////////////////////////////////////////////////////// 507 508 // MetaData 509 510 /** 511 * Returns a String holding the name of the column name for the column number 512 * that was passed in as a parameter this method is for the Implementation of 513 * the TableModel Interface 514 * 515 * @param column Description of Parameter 516 * @return String the name for the indicated column 517 */ 518 public String getColumnName(int column) 519 { 520// System.err.println("getColumnName for -->" + (new Integer(column)).toString() + " is --->" + columnNames[column]); 521 if (columnNames[column] != null) 522 { 523 return columnNames[column]; 524 } 525 else 526 { 527 return ""; 528 } 529 } 530 531 532 /** 533 * This method returns the Java Class type held in the specified column. it will 534 * be String.class, Boolean.class, Integer.class etc. this method is for the 535 * Implementation of the TableModel Interface 536 * 537 * @param column Description of Parameter 538 * @return Class the Java Class representation of the object held in the 539 * specified column. 540 */ 541 public Class getColumnClass(int column) 542 { 543 int type; 544 try 545 { 546 type = metaData.getColumnType(column + 1); 547 } 548 catch (SQLException e) 549 { 550 return super.getColumnClass(column); 551 } 552 553 switch (type) 554 { 555 case Types.CHAR: 556 case Types.VARCHAR: 557 case Types.LONGVARCHAR: 558 return String.class; 559 case Types.BIT: 560 return Boolean.class; 561 case Types.TINYINT: 562 case Types.SMALLINT: 563 case Types.INTEGER: 564 return Integer.class; 565 case Types.BIGINT: 566 return Long.class; 567 case Types.FLOAT: 568 case Types.DOUBLE: 569 return Double.class; 570 case Types.DATE: 571 return java.sql.Date.class; 572 default: 573 return Object.class; 574 } 575 } 576 577 578 /** 579 * This tells you if the specified cell is editable(ie writeable). this method 580 * is for the Implementation of the TableModel Interface 581 * 582 * @param row Description of Parameter 583 * @param column Description of Parameter 584 * @return The CellEditable value 585 */ 586 public boolean isCellEditable(int row, int column) 587 { 588 try 589 { 590 return metaData.isWritable(column + 1); 591 } 592 catch (SQLException e) 593 { 594 return false; 595 } 596 } 597 598 599 /** 600 * Provides and accessor for the number of columns in the table model. this method 601 * is for the Implementation of the TableModel Interface 602 * 603 * @return int the number of columns in the table model 604 */ 605 public int getColumnCount() 606 { 607 return columnNames.length; 608 } 609 610 // Data methods 611 612 /** 613 * Provides and accessor for the number of rows in the table model. this method 614 * is for the Implementation of the TableModel Interface 615 * 616 * @return int the number of rows in the table model 617 */ 618 public int getRowCount() 619 { 620 return rows.size(); 621 } 622 623 624 /** 625 * Provides and accessor for the object at a specific cell in the table model. 626 * this method is for the Implementation of the TableModel Interface 627 * 628 * @param aRow Description of Parameter 629 * @param aColumn Description of Parameter 630 * @return Object the Object at the specified cell in the table model 631 */ 632 public Object getValueAt(int aRow, int aColumn) 633 { 634 Vector row = (Vector) rows.elementAt(aRow); 635 return row.elementAt(aColumn); 636 } 637 638 639 /** 640 * This method takes a String and executes as an SQL statement on the connected 641 * Database. It enters all the results as rows in the table model that this class 642 * represents 643 * 644 * @param query Description of Parameter 645 * @return boolean flag to specify if the query was successful 646 */ 647 public boolean executeQuery(String query) 648 { 649 boolean retVal = true; 650 if (connection == null) 651 { 652 System.err.println("There is no database to execute the query."); 653 return false; 654 } 655 if (statement == null) 656 { 657 System.err.println("The query string that was passed to the JDBCAdapter was null."); 658 return false; 659 } 660 if (getErrorCondition()) 661 { 662 return false; 663 } 664 665 try 666 { 667 resultSet = statement.executeQuery(query); 668 metaData = resultSet.getMetaData(); 669 670 int numberOfColumns = metaData.getColumnCount(); 671 columnNames = new String[numberOfColumns]; 672 // Get the column names and cache them. 673 // Then we can close the connection. 674// System.err.println("!!Debug!! Columns Retrieved"); 675 for (int column = 0; column < numberOfColumns; column++) 676 { 677 columnNames[column] = metaData.getColumnLabel(column + 1); 678// System.err.println(columnNames[column]); 679 } 680 681 // Get all rows. 682 rows = new Vector(); 683 while (resultSet.next()) 684 { 685 Vector newRow = new Vector(); 686 for (int i = 1; i <= getColumnCount(); i++) 687 { 688 newRow.addElement(resultSet.getObject(i)); 689 } 690 rows.addElement(newRow); 691 } 692 // close(); Need to copy the metaData, bug in jdbc:odbc driver. 693 fireTableChanged(null); // Tell the listeners a new table has arrived. 694 } 695 catch (SQLException ex) 696 { 697 retVal = false; 698 setErrorCondition(true); 699 System.err.println("JDBCAdapter: SQL Error"); 700 System.err.println(ex); 701 } 702 return retVal; 703 } 704 705 706 /** 707 * This method performs some clean up for the class. If there is still JDBC objects 708 * open... it closes them so we can efinish up with this class cleanly. 709 */ 710 public void close() 711 { 712 System.out.println("Closing db connection"); 713 try 714 { 715 if (resultSet != null) 716 { 717 resultSet.close(); 718 } 719 if (statement != null) 720 { 721 statement.close(); 722 } 723 if (connection != null) 724 { 725 connection.close(); 726 } 727 } 728 catch (Exception ex) 729 { 730 System.out.println("Can't Close db Connection exception caught"); 731 } 732 } 733 734 735 /** 736 * Provides a method to get the Object data into a String form so it can be put 737 * into the DB. It returns the specified Object in the form of a String. 738 * 739 * @param column Description of Parameter 740 * @param value Description of Parameter 741 * @return string the String representation of the data Object you supplied 742 */ 743 public String dbRepresentation(int column, Object value) 744 { 745 int type; 746 747 if (value == null) 748 { 749 return "null"; 750 } 751 752 try 753 { 754 type = metaData.getColumnType(column + 1); 755 } 756 catch (SQLException e) 757 { 758 return value.toString(); 759 } 760 761 switch (type) 762 { 763 case Types.INTEGER: 764 case Types.DOUBLE: 765 case Types.FLOAT: 766 return value.toString(); 767 case Types.BIT: 768 return ((Boolean) value).booleanValue() ? "1" : "0"; 769 case Types.DATE: 770 return value.toString(); // This will need some conversion. 771 default: 772 return "\"" + value.toString() + "\""; 773 } 774 775 } 776 777 778 /** 779 * Get method for this field 780 * 781 * @return The Rows value 782 */ 783 protected Vector getRows() 784 { 785 return rows; 786 } 787 788 789 /** 790 * This method is here to ensure that we exit cleanly from the JDBC connections 791 * that might have been made. It simply calls the close() method. 792 * 793 * @exception Throwable Description of Exception 794 */ 795 protected void finalize() throws Throwable 796 { 797 close(); 798 // super.finalize(); 799 } 800 801 802 /** 803 * Get method for this field 804 * 805 * @return Description of the Returned Value 806 */ 807 private String getdbVendor() 808 { 809 return dbVendor; 810 } 811 812 813 /** 814 * Get method for this field 815 * 816 * @return Description of the Returned Value 817 */ 818 private String getdbName() 819 { 820 return dbName; 821 } 822 823 824 /** 825 * Get method for this field 826 * 827 * @return Description of the Returned Value 828 */ 829 private String getdbUsername() 830 { 831 return dbUsername; 832 } 833 834 835 /** 836 * Get method for this field 837 * 838 * @return Description of the Returned Value 839 */ 840 private String getdbPassword() 841 { 842 return dbPassword; 843 } 844 845 846 /** 847 * Get method for this field 848 * 849 * @return Description of the Returned Value 850 */ 851 private String getdbServer() 852 { 853 return dbServer; 854 } 855 856 857 /** 858 * Get method for this field 859 * 860 * @return Description of the Returned Value 861 */ 862 private String getdbPort() 863 { 864 return dbPort; 865 } 866} 867 868