001package bradleyross.j2ee.servlets; 002import bradleyross.library.database.DatabaseProperties; 003import bradleyross.library.helpers.GenericPrinter; 004import bradleyross.library.helpers.StringHelpers; 005import java.io.IOException; 006import java.io.PrintWriter; 007import java.io.StringWriter; 008import java.sql.SQLException; 009import java.sql.ResultSet; 010import java.sql.ResultSetMetaData; 011import java.sql.DatabaseMetaData; 012import java.sql.Types; 013import java.sql.Driver; 014import java.util.Vector; 015import javax.servlet.ServletConfig; 016import javax.servlet.ServletException; 017import javax.servlet.http.HttpServlet; 018import javax.servlet.http.HttpServletRequest; 019import javax.servlet.http.HttpServletResponse; 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022import bradleyross.library.helpers.ExceptionHelper; 023/** 024 * Servlet for showing database schema information using 025 * {@link DatabaseMetaData}. 026 * 027 * <p>This was an earlier attempt to do an autodocumenter for 028 * database schemas. There was a later version that also listed indices 029 * and foreign keys and used better formatting, and I'm trying to locate it.</p> 030 * 031 * <p>It should be noted that SQL Server does not have a BOOLEAN 032 * type but uses an integer value instead for result sets 033 * containing boolean data. A value of 0 indicates false 034 * while a value of 1 indicates true.</p> 035 * 036 * <p>The servlet uses the init parameters class, system, and account.</p> 037 * <ul> 038 * <li>class is the name of the class that is a subclass of 039 * {@link DatabaseProperties} that serves to connect the databases.</li> 040 * <li>system is the identifier for the database to be used.</li> 041 * <li>account is the name of the account to be used.</li> 042 * </ul> 043 * 044 * @author Bradley Ross 045 * @see DatabaseMetaData#getCrossReference(String, String, String, String, String, String) 046 * @see DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean) 047 * @see DatabaseMetaData#getTables(String, String, String, String[]) 048 * @see DatabaseMetaData#getImportedKeys(String, String, String) 049 * @see DatabaseMetaData#getExportedKeys(String, String, String) 050 */ 051@SuppressWarnings("serial") 052public class ShowSchema extends HttpServlet 053{ 054 Logger log = LoggerFactory.getLogger(this.getClass()); 055 ExceptionHelper logger = new ExceptionHelper(log); 056 /** 057 * True if servlet was correctly instantiated. 058 */ 059 protected boolean isValid = true; 060 /** 061 * Name of class for handling database. 062 */ 063 protected String databaseClassName = null; 064 /** 065 * Class for handling database. 066 */ 067 protected Class<?> databaseClass = null; 068 /** 069 * Name of system for database connection. 070 */ 071 protected String databaseSystem = null; 072 /** 073 * Description of database. 074 */ 075 protected String databaseDescription = null; 076 /** 077 * Name of account to be used for database connection. 078 */ 079 protected String databaseAccount = null; 080 /** 081 * List of warning or error messages generated by this application. 082 */ 083 protected Vector<String> errorMessages = new Vector<String>(); 084 /** 085 * List of informative messages generated by this application. 086 */ 087 protected Vector<String> infoMessages = new Vector<String>(); 088 /** 089 * Generates an error message for the application. 090 * @param title Text to appear in title 091 * @param message Text to appear in body of message 092 * @return HTML page 093 * @throws IOException if io errors 094 */ 095 public String buildErrorMessage(String title, String message) throws IOException 096 { 097 StringWriter writer = new StringWriter(); 098 GenericPrinter output = new GenericPrinter(writer); 099 output.println("<html><head>"); 100 output.println("<title>" + StringHelpers.escapeHTML(title) + "</title>"); 101 output.println("</head><body"); 102 output.println("<h1>" + StringHelpers.escapeHTML(title) + "</h1>"); 103 output.println("<p>" + StringHelpers.escapeHTML(message) + "</p>"); 104 if (errorMessages.size() > 0) 105 { 106 output.println("<h2>Possible Problems</h2>"); 107 output.println("<ul>"); 108 for (int i = 0; i < errorMessages.size(); i++) 109 { 110 output.println("<li>" + StringHelpers.escapeHTML(errorMessages.elementAt(i)) 111 + "</li>"); 112 } 113 output.println("</ul"); 114 } 115 if (infoMessages.size() > 0) 116 { 117 output.println("<h2>Messages</h2>"); 118 output.println("<ul>"); 119 for (int i = 0; i < infoMessages.size(); i++) 120 { 121 output.println("<li>" + StringHelpers.escapeHTML(infoMessages.elementAt(i)) 122 + "</li>"); 123 } 124 output.println("</ul>"); 125 } 126 output.println("</body></html>"); 127 String result = writer.toString(); 128 output.close(); 129 return result; 130 } 131 132 /** 133 * Determines whether an item in the database is to be included in the 134 * reports. 135 * 136 * <p>When dealing with SQLServer, dbo.dtproperties was showing up on the list 137 * of tables even though it was a system table. The other system tables 138 * weren't appearing.</p> 139 * 140 * @param data Object describing data connection 141 * @param catalog Name of catalog for item in database 142 * @param schema Name of schema for item in database 143 * @param item Name of item in database 144 * @return True if item is to be included in report 145 */ 146 protected boolean isIncluded(DatabaseProperties data, String catalog, String schema, String item) 147 { 148 String database = data.getDbms(); 149 if (database == null) 150 { 151 return true; 152 } 153 else if (database.equalsIgnoreCase("sqlserver")) 154 { 155 try 156 { 157 String schemaTest = null; 158 if (schema == null) 159 { 160 schemaTest = new String(); 161 } 162 else 163 { 164 schemaTest = schema; 165 } 166 if (schemaTest.equalsIgnoreCase("dbo") && item.equalsIgnoreCase("dtproperties")) 167 { 168 return false; 169 } 170 else if (schemaTest.equalsIgnoreCase("sys")) 171 { 172 return false; 173 } 174 else if (schemaTest.equalsIgnoreCase("INFORMATION_SCHEMA")) 175 { 176 return false; 177 } 178 else 179 { 180 return true; 181 } 182 } 183 catch (Exception e) 184 { 185 return true; 186 } 187 } 188 else 189 { 190 return true; 191 } 192 } 193 /** 194 * Default constructor. 195 * 196 * <p>The default constructor is used by the Tomcat application 197 * server when setting up the servlet. The default 198 * constructor must be explicitly defined since there 199 * is an explicit constructor for the class.</p> 200 */ 201 public ShowSchema() 202 { ; } 203 /** 204 * Constructor to allow the methods to be used by a stand-alone 205 * application. 206 * @param className Name of class for defining database connections. 207 * @param system Database system for which connection is to be made. 208 * @param account Account name to be used in connecting to the 209 * database. 210 */ 211 public ShowSchema(String className, String system, String account) 212 { 213 isValid = true; 214 databaseClassName = className; 215 databaseSystem = system; 216 databaseAccount = account; 217 try 218 { 219 databaseClass = Class.forName(className); 220 } 221 catch (ClassNotFoundException e) 222 { 223 errorMessages.add("Unable to find class " + className); 224 isValid = false; 225 return; 226 } 227 if (!DatabaseProperties.class.isAssignableFrom(databaseClass)) 228 { 229 errorMessages.add("Class " + className + " is not subclass of DatabaseProperties"); 230 isValid = false; 231 return; 232 } 233 infoMessages.add("Initialization with ShowSchema complete: " + 234 className + ", " + system + ", " + account); 235 } 236 /** 237 * Obtain a connection to the database based on the initialization 238 * parameters for the servlet. 239 * 240 * @see #databaseAccount 241 * @see #databaseSystem 242 * @see #databaseClassName 243 * @return Database connection information 244 */ 245 protected DatabaseProperties getData() 246 { 247 DatabaseProperties data = null; 248 if (!isValid) 249 { 250 return null; 251 } 252 try 253 { 254 data = (DatabaseProperties) databaseClass.newInstance(); 255 } 256 catch (InstantiationException e) 257 { 258 errorMessages.add("Error while instantiating DatabaseProperties object"); 259 errorMessages.add(e.getClass().getName() + " " + e.getMessage()); 260 isValid = false; 261 return null; 262 } 263 catch (IllegalAccessException e) 264 { 265 errorMessages.add("Error while instantiating DatabaseProperties object"); 266 errorMessages.add(e.getClass().getName() + " " + e.getMessage()); 267 isValid = false; 268 return null; 269 } 270 data.setDatabaseInstance(databaseSystem, databaseAccount); 271 try 272 { 273 data.connect(); 274 } 275 catch (SQLException e) 276 { 277 errorMessages.add("Error while opening database connection"); 278 errorMessages.add(data.showAttributes()); 279 errorMessages.add(e.getClass().getName() + " " + e.getMessage()); 280 isValid = false; 281 } 282 if (!isValid) 283 { 284 return null; 285 } 286 infoMessages.add("Database connection has been opened"); 287 return data; 288 } 289 /** 290 * Initializes object for use with servlets. 291 * <p>The following servlet configuration items are used.</p> 292 * <ul> 293 * <li>class - Subclass of DatabaseProperties that is used to connect with the 294 * database.</li> 295 * <li>system</li> 296 * <li>account</li> 297 * </ul> 298 * @param configIn Servlet configuration object 299 * @throws ServletException if servlet problem 300 * 301 */ 302 public void init(ServletConfig configIn) throws ServletException 303 { 304 isValid = true; 305 try 306 { 307 databaseClassName = configIn.getInitParameter("class"); 308 databaseSystem = configIn.getInitParameter("system"); 309 databaseAccount = configIn.getInitParameter("account"); 310 databaseClass = Class.forName(databaseClassName); 311 } 312 catch (ClassNotFoundException e) 313 { 314 isValid = false; 315 return; 316 } 317 if (!DatabaseProperties.class.isAssignableFrom(databaseClass)) 318 { 319 errorMessages.add("Class " + databaseClassName + " is not subclass of DatabaseProperties"); 320 isValid = false; 321 return; 322 } 323 } 324 /** 325 * Place error message on web page if exception is encountered. 326 * 327 * @param e Exception 328 * @param output Output device for servlet writer 329 * @param message message to be paced on error page 330 * @throws IOException if io errors 331 */ 332 protected void ProblemFound (Exception e, GenericPrinter output, String message) throws IOException 333 { 334 output.println("<html><head>"); 335 output.println("<title>Error encountered in processing database</title>"); 336 output.println("</head><body>"); 337 output.println("<h1>Problem encountered in connecting to database</h1>"); 338 output.println("<p>" + StringHelpers.escapeHTML(message) + "</p>"); 339 output.println("<p>System name is " + databaseSystem + "</p>"); 340 output.println("<p>Account name is " + databaseAccount + "</p>"); 341 output.println("<p>" + StringHelpers.escapeHTML(e.getClass().getName()) + " " + 342 StringHelpers.escapeHTML(e.getMessage()) + "</p>"); 343 StringWriter sw = new StringWriter(); 344 PrintWriter pw = new PrintWriter(sw); 345 e.printStackTrace(pw); 346 output.println("<p>" + StringHelpers.escapeHTML(sw.toString()) + "</p>"); 347 output.println("</body></html>"); 348 } 349 /** 350 * This is the method that is executed each time a request is made for the 351 * web page. 352 * 353 * @param req Request information 354 * @param res Response information 355 * @throws IOException if io errors 356 */ 357 public void service (HttpServletRequest req, 358 HttpServletResponse res) throws IOException 359 { 360 // String rootName = req.getContextPath() + req.getServletPath(); 361 DatabaseProperties data = null; 362 PrintWriter writer = null; 363 GenericPrinter generic = null; 364 String pathInfo = null; 365 res.setContentType("text/html"); 366 writer = res.getWriter(); 367 generic = new GenericPrinter(writer); 368 pathInfo = req.getPathInfo(); 369 370 try 371 { 372 data = (DatabaseProperties) databaseClass.newInstance(); 373 data.setDatabaseInstance(databaseSystem, databaseAccount); 374 data.connect(); 375 databaseDescription = data.getSystemDescription(); 376 if (databaseDescription == null) 377 { 378 databaseDescription = new String(); 379 } 380 } 381 catch (InstantiationException e) 382 { 383 logger.error("Problem setting up database connection: ", e); 384 ProblemFound(e, generic, "Problem setting up database connection: " + 385 "InstantiationException"); 386 return; 387 } 388 catch (IllegalAccessException e) 389 { 390 ProblemFound(e, generic, "Problem setting up database connection: " + 391 "IllegalAccessException"); 392 return; 393 } 394 catch (SQLException e) 395 { 396 ProblemFound(e, generic, "Problem setting up database connection: " + 397 "SQLException"); 398 return; 399 } 400 /* 401 * Now that the page is open, carry out the appropriate action for 402 * writing the web page. 403 */ 404 if (pathInfo == null || pathInfo.length() == 0 || pathInfo.equals("/") || 405 pathInfo.equalsIgnoreCase("/main.do")) 406 { 407 // generic.print(buildRootPage(data, rootName, debugLevel)); 408 processRootPage(data, generic, req, res); 409 } 410 else if (pathInfo.equalsIgnoreCase("/listtables") || 411 pathInfo.equalsIgnoreCase("/listtables.do")) 412 { 413 processListTables(data, generic, req, res); 414 } 415 else if (pathInfo.equalsIgnoreCase("/listviews") || 416 pathInfo.equalsIgnoreCase("/listviews.do")) 417 { 418 processListViews(data, generic, req, res); 419 } 420 else if (pathInfo.equalsIgnoreCase("/listprocedures") || 421 pathInfo.equalsIgnoreCase("/listprocedures.do")) 422 { 423 processListProcedures(data, generic, req, res); 424 } 425 else if (pathInfo.equalsIgnoreCase("/databaseinformation")|| 426 pathInfo.equalsIgnoreCase("/databaseinformation.do")) 427 { 428 processDatabaseInformation(data, generic, req, res); 429 } 430 else if (pathInfo.equalsIgnoreCase("/listudts") || 431 pathInfo.equalsIgnoreCase("/listudts.do")) 432 { 433 processUDTInformation(data, generic, req, res); 434 } 435 else if (pathInfo.equalsIgnoreCase("/describetable") || 436 pathInfo.equalsIgnoreCase("/describetable.do")) 437 { 438 processDescribeTable(data, generic, req, res); 439 } 440 else 441 { 442 // generic.print(buildRootPage(data, rootName, debugLevel)); 443 processRootPage(data,generic, req, res); 444 } 445 /* 446 * Close the database now that the page is complete. 447 */ 448 try 449 { 450 data.close(); 451 } 452 catch (SQLException e) 453 { 454 writer.println("<p>Problem closing database connection</p>"); 455 writer.println("<p>" + 456 StringHelpers.escapeHTML(e.getClass().getName() + " " + e.getMessage()) + 457 "</p>"); 458 } 459 writer.println("</body></html>"); 460 } 461 /** 462 * Generate the root page for schema information for the database. 463 * @param data Object describing database connection 464 * @param output Object for writing web page 465 * @param req HTTP request information 466 * @param res HTTP response information 467 * @throws IOException if io errors 468 */ 469 protected void processRootPage(DatabaseProperties data, GenericPrinter output, 470 HttpServletRequest req, HttpServletResponse res) throws IOException 471 { 472 String rootName = req.getContextPath() + req.getServletPath(); 473 output.println("<html><head>"); 474 output.println("<title>Database Information</title>"); 475 output.println("</head><body>"); 476 output.println("<p>The root URL is " + rootName + "</p>"); 477 output.println("<h1>Database Schema</h1>"); 478 output.println("<ul>"); 479 output.println("<li><a href=\"" + rootName + "/DatabaseInformation\">Database Information</a></li>"); 480 output.println("<li><a href=\"" + rootName + "/ListTables\">List Tables</a></li>"); 481 output.println("<li><a href=\"" + rootName + "/ListViews\">List Views</a></li>"); 482 output.println("<li><a href=\"" + rootName + "/ListProcedures\">List Procedures</a></li>"); 483 output.println("<li><a href=\"" + rootName + "/ListUDTs\">List User Defined Types (UDT)</a></li>"); 484 output.println("</ul>"); 485 output.println("<p>DBMS is " + data.getDbms()); 486 output.println("<p>System is " + data.getSystem() + "</p>"); 487 output.println("<p>" + StringHelpers.escapeHTML(data.showAttributes()) + "</p>"); 488 output.println("The URL's for this process start with " + 489 req.getContextPath() + req.getServletPath()); 490 } 491 /** 492 * Generate the list of tables in the database. 493 * @param data Object describing database connection 494 * @param output Object for writing web page 495 * @param req HTTP request information 496 * @param res HTTP response information 497 * @throws IOException if io errors 498 */ 499 protected void processListTables(DatabaseProperties data, GenericPrinter output, 500 HttpServletRequest req, HttpServletResponse res) throws IOException 501 { 502 int counter = 0; 503 DatabaseMetaData meta = null; 504 ResultSet rs = null; 505 String list[] = { "TABLE" }; 506 507 String rootName = req.getContextPath() + req.getServletPath(); 508 509 output.println("<html><head>"); 510 output.println("<title>" + rootName + "/ListTables</title>"); 511 output.println("</head><body>"); 512 output.println("<h1>List of Tables</h1>"); 513 if (databaseDescription.length() > 0) 514 { 515 output.println("<h2>" + databaseDescription + "</h2>"); 516 } 517 try 518 { 519 meta = data.getConnection().getMetaData(); 520 rs = meta.getTables(null, null, null, list); 521 } 522 catch (SQLException e) 523 { 524 output.println("<p>Unable to get list of tables</p>"); 525 output.println(StringHelpers.escapeHTML(e.getClass().getName() + " " + 526 e.getMessage())); 527 output.println("</body></html>"); 528 return; 529 } 530 try 531 { 532 output.println("<table border><tr>"); 533 output.println("<td><b>Catalog</b></td><td><b>Schema</b></td><td><b>Table</b></td>"); 534 output.println("<td><b>Remarks</b></td></tr>"); 535 536 while (rs.next()) 537 { 538 String catalog = rs.getString("TABLE_CAT"); 539 if (rs.wasNull()) { 540 catalog = new String(); 541 } 542 543 String schema = rs.getString("TABLE_SCHEM"); 544 if (rs.wasNull()) { 545 schema = new String(); 546 } 547 String item = rs.getString("TABLE_NAME"); 548 if (!isIncluded(data, catalog, schema, item)) 549 { 550 continue; 551 } 552 counter++; 553 output.println("<tr>"); 554 output.println("<td>" + catalog + "</td><td>" + schema + 555 "</td><td>" + 556 "<a href=\"" + rootName + "/DescribeTable?CATALOG=" + catalog + 557 "&SCHEMA=" + schema + "&ITEM=" + item + 558 "\">" + item + "</a></td><td>" + 559 rs.getString("REMARKS") + "</td>"); 560 output.println("</tr>"); 561 } 562 output.println("</table>"); 563 } 564 catch (SQLException e) 565 { 566 output.println("<p>A problem was encountered while creating the list of tables</p>"); 567 } 568 output.println("<p>There are " + Integer.toString(counter) + " tables</p>"); 569 output.println("<hr />"); 570 output.println("<p><a href=\"" + rootName + "\">Return to root page</a></p>"); 571 } 572 /** 573 * Generate the list of views in the database. 574 * @param data Object describing database connection 575 * @param output Object for writing web page 576 * @param req HTTP request information 577 * @param res HTTP response information 578 * @throws IOException if io errors 579 */ 580 protected void processListViews(DatabaseProperties data, GenericPrinter output, 581 HttpServletRequest req, HttpServletResponse res) throws IOException 582 { 583 if (!isValid) 584 { 585 586 } 587 String list[] = { "VIEW" }; 588 String catalog = null; 589 String schema = null; 590 String item = null; 591 ResultSet rs = null; 592 DatabaseMetaData meta = null; 593 int counter = 0; 594 String rootName = req.getContextPath() + req.getServletPath(); 595 output.println("<html><head>"); 596 output.println("<title>" + rootName + "/ListViews</title>"); 597 output.println("</head><body>"); 598 output.println("<h1>List of Views</h1>"); 599 try 600 { 601 meta = data.getConnection().getMetaData(); 602 rs = meta.getTables(null, null, null, list); 603 output.println("<table border><tr><td></td><td><b>Catalog</b></td>" + 604 "<td><b>Schema</b></td><td><b>View Name</b></td>" + 605 "<td><b>Remarks</b></td></tr>"); 606 while (rs.next()) 607 { 608 catalog = rs.getString("TABLE_CAT"); 609 schema = rs.getString("TABLE_SCHEM"); 610 item = rs.getString("TABLE_NAME"); 611 if (!isIncluded(data, catalog, schema, item)) 612 { 613 continue; 614 } 615 counter++; 616 output.println("<tr><td>" + Integer.toString(counter) + "</td><td>" + 617 catalog + "</td><td>" + schema + "</td><td>" + 618 item + "</td><td>" + rs.getString("REMARKS") + "</td></tr>"); 619 } 620 output.println("</table>"); 621 output.println("<p>There are " + Integer.toString(counter) + " views</p>"); 622 } 623 catch (SQLException e) 624 { 625 output.println("<p>Problem generating list of views</p>"); 626 } 627 628 output.println("<p><a href=\"" + rootName + "\">Return to root page</a></p>"); 629 } 630 /** 631 * Generate the list of procedures in the database. 632 * 633 * @param data Object containing database connection information 634 * @param output Object for writing web page 635 * @param req HTTP request information 636 * @param res HTTP response information 637 * 638 * @throws IOException if io errors 639 * 640 * @see DatabaseMetaData#getProcedures(String, String, String) 641 */ 642 protected void processListProcedures(DatabaseProperties data, GenericPrinter output, 643 HttpServletRequest req, HttpServletResponse res) throws IOException 644 { 645 ResultSet rs = null; 646 DatabaseMetaData meta = null; 647 int counter = 0; 648 String rootName = req.getContextPath() + req.getServletPath(); 649 output.println("<html><head>"); 650 output.println("<title>" + rootName + "/ListProcedures</title>"); 651 output.println("</head><body>"); 652 output.println("<h1>List of Procedures</h1>"); 653 try 654 { 655 meta = data.getConnection().getMetaData(); 656 rs = meta.getProcedures(null, null, null); 657 counter = showResultSet(output, rs ); 658 } 659 catch (SQLException e) 660 { 661 output.println("<p>Unable to get list of procedures</p>"); 662 } 663 output.println("<p>There are " + Integer.toString(counter) + " procedures</p>"); 664 output.println("<p><a href=\"" + rootName + "\">Return to root page</a></p>"); 665 } 666 /** 667 * Generate the list of user defined types for the database system. 668 * 669 * <p>Needs to have code for User Defined Types inserted.</p> 670 * 671 * @param data Database connection information 672 * @param output GenericPrinter object to which material is sent 673 * @param req HTTP request object 674 * @param res HTTP response object 675 * @throws IOException if io problems 676 * 677 * @see DatabaseMetaData#getUDTs(String, String, String, int[]) 678 */ 679 protected void processUDTInformation(DatabaseProperties data, GenericPrinter output, 680 HttpServletRequest req, HttpServletResponse res) throws IOException 681 { 682 String rootName = req.getContextPath() + req.getServletPath(); 683 output.println("<html><head"); 684 output.println("<title>User Defined Types</title>"); 685 output.println("</head><body>"); 686 output.println("<h1>User Defined Types</h1>"); 687 output.println("<hr />"); 688 output.println("<p><a href=\"" +rootName + "\">Return to root page</a></p>"); 689 } 690 /** 691 * Generate a page containing information about the database system. 692 * 693 * @param data Object containing database connection information 694 * @param output Object for writing web page 695 * @param req HTTP request information 696 * @param res HTTP response information 697 * @throws IOException if io problems exist 698 * @see DatabaseMetaData 699 */ 700 protected void processDatabaseInformation(DatabaseProperties data, GenericPrinter output, 701 HttpServletRequest req, HttpServletResponse res) throws IOException 702 { 703 boolean hasMetaData = true; 704 DatabaseMetaData meta = null; 705 Driver driver = data.getDriver(); 706 ResultSet rs = null; 707 String rootName = req.getContextPath() + req.getServletPath(); 708 try 709 { 710 meta = data.getConnection().getMetaData(); 711 } 712 catch (SQLException e) 713 { 714 hasMetaData = false; 715 meta = null; 716 } 717 output.println("<html><head>"); 718 output.println("<title>" + rootName + "/DatabaseInformation</title>"); 719 output.println("</head><body>"); 720 if (!hasMetaData || meta == null) 721 { 722 output.println("<p>Unable to obtain data about database</p>"); 723 output.println("</body></html>"); 724 return; 725 } 726 else 727 { 728 boolean transactions = true; 729 output.println("<p><a href=\"#catalogs\">Catalogs</a> " + 730 "<a href=\"#schemas\">Schemas</a> " + 731 "<a href=\"#tables\">Tables</a> " + 732 "<a href=\"#procedures\">Procedures</a> " + 733 "</p>"); 734 try 735 { 736 String name = meta.getDatabaseProductName(); 737 String version = Integer.toString(meta.getDatabaseMajorVersion()) + 738 "." + Integer.toString(meta.getDatabaseMinorVersion()); 739 transactions = meta.supportsTransactions(); 740 output.println("<h2><a name=\"database\">Database Information</a></h2>"); 741 output.println("<p>Major version: " + Integer.toString(driver.getMajorVersion()) + "</p>"); 742 output.println("<p>Minor version: " + Integer.toString(driver.getMinorVersion()) + "</p>"); 743 output.println("<p>Using database " + name + 744 " Version " + version + "</p>"); 745 output.println("<p>Supports transactions: " + Boolean.toString(transactions) + "</p>"); 746 } 747 catch (SQLException e) 748 { 749 output.println("<p>Unable to get database name and version</p>"); 750 } 751 output.println("<h2><a name=\"catalogs\">Catalog Information</a></h2>"); 752 try 753 { 754 boolean catalogsInDataManipulation = 755 meta.supportsCatalogsInDataManipulation(); 756 boolean catalogAtStart = meta.isCatalogAtStart(); 757 String catalogTerm = meta.getCatalogTerm(); 758 String catalogSeparator = meta.getCatalogSeparator(); 759 if (catalogTerm == null) 760 { 761 output.println("<p>No term for catalogss</p>"); 762 } 763 else if (catalogTerm.length() == 0) 764 { 765 output.println("<p>No term for catalogs</p>"); 766 } 767 else 768 { 769 output.println("<p>Term for catalogs is " + catalogTerm + "</p>"); 770 } 771 output.println("<p>Supports catalogs in data manipulation: " + 772 Boolean.toString(catalogsInDataManipulation) + "</p>"); 773 output.println("<p>Supports catalog name at start of identifier: " + 774 Boolean.toString(catalogAtStart)); 775 if (catalogAtStart) 776 { 777 output.println("<p>Separator for catalog name is <code>" + 778 catalogSeparator + "</code></p>"); 779 } 780 } 781 catch (SQLException e) 782 { 783 output.println("<p>Unable to get information about catalogs</p>"); 784 } 785 /* 786 * Print information on schemas. 787 */ 788 output.println("<h2><a name=\"schemas\">Schema Information</a></h2>"); 789 try 790 { 791 boolean schemasInDataManipulation = 792 meta.supportsSchemasInDataManipulation(); 793 String schemaTerm = meta.getSchemaTerm(); 794 if (schemaTerm == null) 795 { 796 output.println("<p>No term for schemas</p>"); 797 } 798 else if (schemaTerm.length() == 0) 799 { 800 output.println("<p>No term for schemas</p>"); 801 } 802 else 803 { 804 output.println("<p>Term for schemas is " + schemaTerm + "</p>"); 805 } 806 output.println("<p>Supports schemas in data manipulation: " + 807 Boolean.toString(schemasInDataManipulation) + "</p>"); 808 } 809 catch (SQLException e) 810 { 811 output.println("<p>Unable to get information about schemas</p>"); 812 } 813 /* 814 * Print information on tables 815 */ 816 output.println("<h2><a name=\"tables\">Tables</a></h2>"); 817 try 818 { 819 int counter = 0; 820 rs = meta.getTableTypes(); 821 output.println("<p>The table types are </p>"); 822 counter = showResultSet(output, rs); 823 output.println("<p>There are " + Integer.toString(counter) + " table types</p>"); 824 } 825 catch(SQLException e) 826 { 827 output.println("<p>Unable to get information on table types</p>"); 828 } 829 /* 830 * Print information on procedures. 831 */ 832 output.println("<h2><a name=\"procedures\">Procedures</a></h2>"); 833 try 834 { 835 String value = meta.getProcedureTerm(); 836 output.println("<p>Term for procedure is " + value + "</p>"); 837 } 838 catch (SQLException e) 839 { 840 output.println("<p>Unable to get information on procedures</p>"); 841 } 842 } 843 output.println("<hr />"); 844 output.println("<p><a href=\"" + rootName + "\">Return to root page</p>"); 845 } 846 /** 847 * Generate a web page describing the layout of a table. 848 * 849 * @param data Database connection data object 850 * @param output GenericPrinter object to which information is sent 851 * @param req HTTP request object 852 * @param res HTTP response object 853 * @throws IOException if io errors 854 * @see DatabaseMetaData#getTables(String, String, String, String[]) 855 * @see DatabaseMetaData#getColumns(String, String, String, String) 856 * @see DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean) 857 * @see DatabaseMetaData#getExportedKeys(String, String, String) 858 * @see DatabaseMetaData#getImportedKeys(String, String, String) 859 */ 860 protected void processDescribeTable(DatabaseProperties data, GenericPrinter output, 861 HttpServletRequest req, HttpServletResponse res) throws IOException 862 { 863 String catalog = null; 864 String schema = null; 865 String item = null; 866 int counter = -1; 867 String rootName = req.getContextPath() + req.getServletPath(); 868 DatabaseMetaData meta = null; 869 ResultSet rs = null; 870 try 871 { 872 catalog = req.getParameter("CATALOG"); 873 if (catalog.length()==0) { 874 catalog=null; 875 } 876 877 schema = req.getParameter("SCHEMA"); 878 if (schema.length()==0) { 879 schema = null; 880 } 881 item = req.getParameter("ITEM"); 882 output.println("<html><head>"); 883 output.println("<title>Layout of Table " + item + "</title>"); 884 output.println("</head><body>"); 885 output.println("<h1>Layout of Table " + item + "</h1>"); 886 if (catalog != null) { 887 output.println("<p>Catalog: " + catalog + "</p>"); 888 } 889 if (schema != null) { 890 output.println("<p>Schema: " + schema + "</p>"); 891 } 892 output.println("<p>Running processDescribeTable</p>"); 893 meta = data.getConnection().getMetaData(); 894 output.println("<p>Result of getColumns</p>"); 895 rs = meta.getColumns(catalog, schema, item, (String) null); 896 output.println("<p>Information on columns</p>"); 897 counter = showResultSet(output, rs); 898 output.println("<p>There are " + Integer.toString(counter) + " columns</p>"); 899 rs = null; 900 output.println("<hr />"); 901 output.println("<p>Result of getIndexInfo</p>"); 902 rs = meta.getIndexInfo(catalog, schema, item, false, false); 903 counter = showResultSet(output, rs); 904 output.println("<p>There are " + Integer.toString(counter) + " indexes</p>"); 905 rs = null; 906 output.println("<hr />"); 907 output.println("<p>Result of getImportedKeys</p>"); 908 rs = meta.getImportedKeys(catalog, schema, item); 909 counter = showResultSet(output, rs); 910 output.println("<p>There are " + Integer.toString(counter) + " imported keys</p>"); 911 rs = null; 912 output.println("<hr />"); 913 output.println("<p>Result of getExportedKeys</p>"); 914 rs = meta.getExportedKeys(catalog, schema, item); 915 counter = showResultSet(output, rs); 916 output.println("<p>There are " + Integer.toString(counter) + " exported keys</p>"); 917 rs = null; 918 output.println("<hr />"); 919 output.println("<p><a href=\"" + rootName + "\">Return to root page</a></p>"); 920 } 921 catch (SQLException e) 922 { 923 System.out.println("<p>Unable to get information</p>"); 924 System.out.println("<hr />"); 925 System.out.println("<p><a href=\"" + rootName + "\">Return to root page</a></p>"); 926 } 927 } 928 929 /** 930 * Displays a result set as an HTML table. 931 * @param output Object for printing to HTML page 932 * @param rs Result set to be processed 933 * @return number of rows 934 * @throws IOException if io errors 935 */ 936 protected int showResultSet(GenericPrinter output, ResultSet rs) throws IOException 937 { 938 int counter = 0; 939 ResultSetMetaData rsmeta = null; 940 try 941 { 942 rsmeta = rs.getMetaData(); 943 } 944 catch (SQLException e) 945 { 946 output.println("<p>Unable to get metadata</p>"); 947 output.println(StringHelpers.escapeHTML(e.getClass().getName() + " " + 948 e.getMessage())); 949 output.println("</body></html>"); 950 return -1; 951 } 952 try 953 { 954 int columnCount = rsmeta.getColumnCount(); 955 int columnType[] = new int[columnCount]; 956 output.println("<table border><tr><td> </td>"); 957 for (int i = 1; i <= columnCount; i++) 958 { 959 columnType[i-1] = rsmeta.getColumnType(i); 960 output.println("<td><b><code>" + 961 StringHelpers.escapeHTML(rsmeta.getColumnName(i)) + "</code></b></td>"); 962 } 963 output.println("</tr>"); 964 while (rs.next()) 965 { 966 counter++; 967 output.println("<tr><td align=\"right\">" + Integer.toString(counter) + 968 "</td>"); 969 for (int i = 1; i <= columnCount; i++) 970 { 971 int localType = columnType[i-1]; 972 if (localType == Types.BOOLEAN) 973 { 974 output.println("<td>" + Boolean.toString(rs.getBoolean(i)) + "</td>"); 975 } 976 else if (localType == Types.VARCHAR || localType == Types.CHAR) 977 { 978 output.println("<td><code>" + StringHelpers.escapeHTML(rs.getString(i)) + "</code></td>"); 979 } 980 else 981 { 982 output.println("<td align=\"right\"><code>" + 983 StringHelpers.escapeHTML(rs.getString(i)) + "</code></td>"); 984 } 985 } 986 output.println("</tr>"); 987 } 988 output.println("</table>"); 989 } 990 catch (SQLException e) 991 { 992 output.println("<p>Problems generating list</p>"); 993 return -1; 994 } 995 return counter; 996 } 997}