View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/devgui/XMLConfigGenerator.java,v 1.18 2006/01/13 21:22:56 hkollmann Exp $
3    * $Revision: 1.18 $
4    * $Date: 2006/01/13 21:22:56 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.devgui;
25  
26  import org.dbforms.config.ForeignKey;
27  import org.dbforms.config.Reference;
28  
29  import java.sql.*;
30  
31  import java.util.*;
32  
33  
34  
35  /***
36   * DOCUMENT ME!
37   *
38   * @author $author$
39   * @version $Revision: 1.18 $
40   */
41  public class XMLConfigGenerator implements PropertyNames {
42     // the following types are known inside class org.dbforms.Field:
43     static final String[] knownFieldTypes = {
44                                                "tinyint",
45                                                "int",
46                                                "smallint",
47                                                "integer",
48                                                "bigint", // mapped to INTEGER
49     "float",
50                                                "real", // mapped to FLOAT
51     "double", // mapped to DOUBLE
52     "numeric",
53                                                "decimal",
54                                                "number", // mapped to NUMERIC
55     "char",
56                                                "varchar",
57                                                "longchar",
58                                                "nvarchar", // mapped to CHAR
59     "blob",
60                                                "image", // mapped to BLOB
61     "diskblob", // mapped to DISKBLOB
62     "date", // mapped to DATE
63     "timestamp" // mapped to TIMESTAMP
64                                             };
65     private static final int DBMS_MYSQL = 1;
66     private static final int DBMS_IBMDB2 = 2;
67  
68     /***
69      * DOCUMENT ME!
70      *
71      * @param dbmd DOCUMENT ME!
72      * @param includeCatalog DOCUMENT ME!
73      * @param catalogSeparator DOCUMENT ME!
74      * @param includeSchema DOCUMENT ME!
75      * @param schemaSeparator DOCUMENT ME!
76      * @param knownTables DOCUMENT ME!
77      * @param foreignKeyTryGetCrossReferences DOCUMENT ME!
78      * @param catalogNames DOCUMENT ME!
79      * @param schemaNames DOCUMENT ME!
80      * @param tableNames DOCUMENT ME!
81      *
82      * @return DOCUMENT ME!
83      */
84     public static HashMap getForeignKeyInformation(DatabaseMetaData dbmd,
85                                                    boolean          includeCatalog,
86                                                    String           catalogSeparator,
87                                                    boolean          includeSchema,
88                                                    String           schemaSeparator,
89                                                    Vector           knownTables,
90                                                    boolean          foreignKeyTryGetCrossReferences,
91                                                    Vector           catalogNames,
92                                                    Vector           schemaNames,
93                                                    Vector           tableNames) {
94        HashMap hm = null;
95  
96        if (foreignKeyTryGetCrossReferences) {
97           try {
98              hm = new HashMap();
99  
100             // following method accepts no pattern, so we just pass nulls and read all
101             // available information:
102             ResultSet rsk = dbmd.getCrossReference(null, null, null, null,
103                                                    null, null);
104 
105             while (rsk.next()) {
106                addSingleReference(hm, rsk, knownTables, includeCatalog,
107                                   catalogSeparator, includeSchema,
108                                   schemaSeparator);
109             }
110          } catch (SQLException ex) {
111             ex.printStackTrace();
112             hm = null;
113          }
114       }
115 
116       if (hm == null) { // above method not tried or failed
117 
118          try {
119             hm = new HashMap();
120 
121             for (int i = 0; i < tableNames.size(); i++) {
122                String    catalogName = (String) catalogNames.get(i);
123                String    schemaName = (String) schemaNames.get(i);
124                String    tableName  = (String) tableNames.get(i);
125                ResultSet rsk        = dbmd.getImportedKeys(catalogName,
126                                                            schemaName, tableName);
127 
128                while (rsk.next()) {
129                   addSingleReference(hm, rsk, knownTables, includeCatalog,
130                                      catalogSeparator, includeSchema,
131                                      schemaSeparator);
132                }
133             }
134          } catch (SQLException ex) {
135             ex.printStackTrace();
136          }
137       }
138 
139       return hm;
140    }
141 
142 
143    /***
144     * DOCUMENT ME!
145     *
146     * @param hm DOCUMENT ME!
147     * @param catalog DOCUMENT ME!
148     * @param schema DOCUMENT ME!
149     * @param table DOCUMENT ME!
150     *
151     * @return DOCUMENT ME!
152     */
153    public static String getForeignKeyTags(HashMap hm,
154                                           String  catalog,
155                                           String  schema,
156                                           String  table) {
157       String  hashKey = emptyIfNull(schema) + "\t" + table;
158       HashMap keyInfo = (HashMap) hm.get(hashKey);
159 
160       if (keyInfo == null) {
161          return "";
162       }
163 
164       StringBuffer sb       = new StringBuffer("");
165       Collection   col      = keyInfo.values();
166       Iterator     forKeyIt = col.iterator();
167 
168       while (forKeyIt.hasNext()) {
169          ForeignKey       fk = (ForeignKey) forKeyIt.next();
170          java.util.Vector v = fk.getReferencesVector();
171          sb.append("\n\t\t<foreign-key  name=\"")
172            .append(fk.getName())
173            .append("\"")
174            .append("\n\t\t      foreignTable=\"")
175            .append(fk.getForeignTable())
176            .append("\"")
177            .append("\n\t\t      displayType=\"")
178            .append((v.size() == 1) ? "select"
179                                    : "none")
180            .append("\"")
181            .append(">\n");
182 
183          for (int jj = 0; jj < v.size(); jj++) {
184             Reference ref = (Reference) v.get(jj);
185             sb.append("\t\t     <reference local=\"")
186               .append(ref.getLocal())
187               .append("\"")
188               .append("\n\t\t              foreign=\"")
189               .append(ref.getForeign())
190               .append("\"/>\n");
191          }
192 
193          sb.append("\t\t</foreign-key>\n");
194       }
195 
196       return sb.toString();
197    }
198 
199 
200    /***
201     * DOCUMENT ME!
202     *
203     * @param projectData DOCUMENT ME!
204     * @param createGuiMessagewindow DOCUMENT ME!
205     *
206     * @return DOCUMENT ME!
207     *
208     * @throws Exception DOCUMENT ME!
209     * @throws SQLException DOCUMENT ME!
210     */
211    public static String createXMLOutput(ProjectData projectData,
212                                         boolean     createGuiMessagewindow)
213                                  throws Exception {
214       String jdbcDriver = projectData.getProperty("jdbcDriver");
215       String jdbcURL  = projectData.getProperty("jdbcURL");
216       String username = projectData.getProperty("username");
217       String password = projectData.getProperty("password");
218 
219       // create boolean variables out of String properties:
220       boolean includeCatalog = projectData.getProperty(INCLUDE_CATALOGNAME)
221                                           .equalsIgnoreCase(TRUESTRING);
222       boolean includeSchema = projectData.getProperty(INCLUDE_SCHEMANAME)
223                                          .equalsIgnoreCase(TRUESTRING);
224       boolean useAutoCommitMode = projectData.getProperty(AUTOCOMMIT_MODE)
225                                              .equalsIgnoreCase(TRUESTRING);
226       boolean useStdTypeNames = projectData.getProperty(WRITE_STD_TYPENAMES)
227                                            .equalsIgnoreCase(TRUESTRING);
228 
229       boolean foreignKeyDetectionActivated = !DEACTIVATED.equalsIgnoreCase(projectData
230                                                                            .getProperty(FOREIGNKEY_DETECTION));
231       boolean foreignKeyTryGetCrossReferences = USE_GETCROSSREFERENCES
232                                                 .equalsIgnoreCase(projectData
233                                                                   .getProperty(FOREIGNKEY_DETECTION));
234       boolean generateDefaultValues = true;
235 
236       // create array of  table types that have to be examined...
237       Vector typesVec = new Vector();
238 
239       if (projectData.getProperty(EXAMINE_TABLES)
240                            .equalsIgnoreCase(TRUESTRING)) {
241          typesVec.add("TABLE");
242       }
243 
244       if (projectData.getProperty(EXAMINE_VIEWS)
245                            .equalsIgnoreCase(TRUESTRING)) {
246          typesVec.add("VIEW");
247       }
248 
249       if (projectData.getProperty(EXAMINE_SYSTABS)
250                            .equalsIgnoreCase(TRUESTRING)) {
251          typesVec.add("SYSTEM TABLE");
252       }
253 
254       String[] types = new String[typesVec.size()];
255 
256       for (int jj = 0; jj < typesVec.size(); jj++) {
257          types[jj] = (String) typesVec.get(jj);
258       }
259 
260       // set values for catalog, schema and table name according to properties:
261       String catalog = projectData.getProperty(CATALOG_SELECTION)
262                                   .equalsIgnoreCase(ALL) ? null
263                                                          : projectData
264                                                            .getProperty(CATALOG);
265 
266       String schemaPattern = projectData.getProperty(SCHEMA_SELECTION)
267                                         .equalsIgnoreCase(ALL) ? null
268                                                                : projectData
269                                                                  .getProperty(SCHEMA);
270 
271       String tableNamePattern = projectData.getProperty(TABLE_SELECTION)
272                                            .equalsIgnoreCase(ALL) ? null
273                                                                   : projectData
274                                                                     .getProperty(TABLE_NAME_PATTERN);
275 
276       String dateFormatTag = projectData.getProperty(DATE_FORMAT)
277                                         .equalsIgnoreCase("") ? ""
278                                                               : ("\n\t<date-format>"
279                                                               + projectData
280                                                                 .getProperty(DATE_FORMAT)
281                                                               + "</date-format>\n\n");
282 
283       System.out.println(": Retrieving metadata using the following properties ");
284       System.out.println("-----------------------------------------------------");
285       System.out.println("jdbcDriver=" + jdbcDriver);
286       System.out.println("jdbcURL=" + jdbcURL);
287       System.out.println("username=" + username);
288       System.out.println("password=(hidden)");
289       System.out.println("catalog=" + catalog);
290       System.out.println("schemaPattern=" + schemaPattern);
291       System.out.println("tableNamePattern=" + tableNamePattern);
292 
293       StringBuffer result = new StringBuffer();
294 
295       boolean      showWarning        = false;
296       int          catalogNameFailure = 0;
297       int          schemaNameFailure  = 0;
298       StringBuffer warningMessage     = new StringBuffer("<html><ul>");
299 
300       Connection   con = null;
301 
302       try {
303          con = createConnection(jdbcDriver, jdbcURL, username, password);
304 
305          result.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n\n<dbforms-config>\n");
306 
307          result.append(dateFormatTag);
308 
309          DatabaseMetaData dbmd = con.getMetaData();
310 
311          // at leat until JDBC 2 there does not seem to be a standard
312          // way to determine, which column is automatically incremented
313          // by dbms. The following is a woraround to support some systems
314          // (contributed by Sebastian Bogaci)
315          // currently we are able to handle:
316          //    MySQL, DB2    : using dbms specific query
317          //    Sybase, (maybe MS-SQL): checking string representation of
318          //                                                       column type
319          boolean           checkForAutoIncFields = false;
320          String            autoIncColumnsQuery = "";
321          String            catalogPlaceholder  = ":catalog";
322          String            schemaPlaceholder   = ":schema";
323          String            tabnamePlaceholder  = ":tabname";
324          int               dbms                = 0;
325          PreparedStatement spCall              = null;
326 
327          try { // this is not mission critical, so own try block
328 
329             String dbmsProductName = dbmd.getDatabaseProductName();
330 
331             if (dbmsProductName != null) {
332                dbmsProductName = dbmsProductName.toLowerCase();
333 
334                if (dbmsProductName.equals("mysql")) {
335                   dbms                  = DBMS_MYSQL;
336                   checkForAutoIncFields = true;
337                   autoIncColumnsQuery   = "SHOW COLUMNS FROM :tabname LIKE ?";
338                } else if (dbmsProductName.startsWith("db2")) {
339                   dbms                  = DBMS_IBMDB2;
340                   checkForAutoIncFields = true;
341                   autoIncColumnsQuery   = "SELECT identity FROM sysibm.syscolumns "
342                                           + "WHERE tbcreator=':schema' and  tbname = ':tabname' AND name = ?";
343                }
344             }
345          } catch (SQLException ignored) {
346             ;
347          }
348 
349          // if user wants to include catalog names in table names,
350          // try to check if DBMS supports this feature:
351          if (includeCatalog) {
352             boolean supportsCatalogInDML = false;
353 
354             try { // this is not mission critical, so own try block 
355                supportsCatalogInDML = dbmd.supportsCatalogsInDataManipulation();
356             } catch (Exception ignored) {
357                ;
358             }
359 
360             if (!supportsCatalogInDML) {
361                showWarning = true;
362                warningMessage.append("<li>Your database system does not seem to support use of  <br>"
363                                      + "  catalog names in data manipulation statements. You should<br> "
364                                      + "  better not include catalog names in table names.");
365             }
366          }
367 
368          // if user wants to includeschema names in table names,
369          // try to check if DBMS supports this feature:
370          if (includeSchema) {
371             boolean supportsSchemaInDML = false;
372 
373             try { // this is not mission critical, so own try block 
374                supportsSchemaInDML = dbmd.supportsSchemasInDataManipulation();
375             } catch (Exception ignored) {
376                ;
377             }
378 
379             if (!supportsSchemaInDML) {
380                showWarning = true;
381                warningMessage.append("<li>Your database system does not seem to support use of <br>"
382                                      + "  schema names in data manipulation statements. You should <br>"
383                                      + "  better not include schema names in table names.");
384             }
385          }
386 
387          // user wants transaction mode, but it is not supported by 
388          // dbms => warning and reset to autocommit mode:
389          if ((!useAutoCommitMode) && (!dbmd.supportsTransactions())) {
390             showWarning = true;
391             warningMessage.append("<li>Transaction mode not supported by DBMS, connection is <br>"
392                                   + "    automatically set to autocommit mode.");
393             useAutoCommitMode = true;
394          }
395 
396          // select transaction mode if desired by user and supported:
397          if (!useAutoCommitMode) {
398             con.setAutoCommit(false);
399          }
400 
401          // try to read catalog separator from DBMS, if needed:
402          String catalogSeparator = "."; // just in case reading value from DB fails
403 
404          if (includeCatalog) {
405             try {
406                catalogSeparator = dbmd.getCatalogSeparator();
407             } catch (SQLException ex) {
408                showWarning = true;
409                warningMessage.append("<li>Error reading catalog separator from database:   <br>"
410                                      + ex.getMessage() + "<br>"
411                                      + "  Using default '" + catalogSeparator
412                                      + "' instead.");
413             }
414          }
415 
416          String schemaSeparator = "."; // isn't that default ? 
417 
418          Vector tableNames   = new Vector();
419          Vector catalogNames = new Vector();
420          Vector schemaNames  = new Vector();
421          Vector knownTables  = new Vector();
422 
423          try {
424             ResultSet tablesRS = dbmd.getTables(catalog, schemaPattern,
425                                                 tableNamePattern, types);
426 
427             while (tablesRS.next()) {
428                catalogNames.add(tablesRS.getString(1));
429                schemaNames.add(tablesRS.getString(2));
430                tableNames.add(tablesRS.getString(3));
431                knownTables.add("" + emptyIfNull(tablesRS.getString(2)) + "\t"
432                                + emptyIfNull(tablesRS.getString(3)));
433             }
434 
435             tablesRS.close();
436          } catch (SQLException ex) {
437             showWarning = true;
438             warningMessage.append("<li>Error while trying to read table names with <br>"
439                                   + "  catalog=" + catalog
440                                   + ",<br>   schemapattern=" + schemaPattern
441                                   + ",<br>   tableNamePattern="
442                                   + tableNamePattern
443                                   + "<br> from database.   <br>Error message:"
444                                   + ex.getMessage() + "<br>");
445          }
446 
447          if (!useAutoCommitMode) {
448             con.commit();
449          }
450 
451          HashMap forKeys = null;
452 
453          if (foreignKeyDetectionActivated) {
454             forKeys = getForeignKeyInformation(dbmd, includeCatalog,
455                                                catalogSeparator, includeSchema,
456                                                schemaSeparator, knownTables,
457                                                foreignKeyTryGetCrossReferences,
458                                                catalogNames, schemaNames,
459                                                tableNames);
460          }
461 
462          if (!useAutoCommitMode) {
463             con.commit();
464          }
465 
466          if (tableNames.size() == 0) {
467             showWarning = true;
468             warningMessage.append("<li> No tables of type <br>(");
469 
470             for (int i = 0; i < types.length; i++)
471                warningMessage.append("'")
472                              .append(types[i])
473                              .append("' ");
474 
475             warningMessage.append(") <br>found with catalog='" + catalog
476                                   + "', schemapattern='" + schemaPattern
477                                   + "',<br>tablename pattern='"
478                                   + tableNamePattern + "'");
479          }
480 
481          boolean autoIncColumnsQueryAlwaysSucceeded = true;
482 
483          for (int i = 0; i < tableNames.size(); i++) {
484             String catalogName = (String) catalogNames.get(i);
485             String schemaName = (String) schemaNames.get(i);
486             String tableName  = (String) tableNames.get(i);
487 
488             result.append("\t<table name=\"");
489 
490             // prepend catalog and schema names to table names
491             // if desired by user and not empty:
492             if (includeCatalog
493                       && (catalogName != null)
494                       && (!catalogName.equalsIgnoreCase(""))) {
495                result.append(catalogName.trim())
496                      .append(catalogSeparator);
497             }
498 
499             if (includeCatalog
500                       && ((catalogName == null)
501                       || catalogName.equalsIgnoreCase(""))) {
502                catalogNameFailure++;
503             }
504 
505             if (includeSchema
506                       && (schemaName != null)
507                       && (!schemaName.equalsIgnoreCase(""))) {
508                result.append(schemaName.trim())
509                      .append(schemaSeparator);
510             }
511 
512             if (includeSchema
513                       && ((schemaName == null)
514                       || schemaName.equalsIgnoreCase(""))) {
515                schemaNameFailure++;
516             }
517 
518             // read primary key into Vector keys:
519             ResultSet rsKeys = dbmd.getPrimaryKeys(catalogName, schemaName,
520                                                    tableName);
521             Vector    keys                 = new Vector();
522             String    defaultVisibleFields = "";
523             boolean   isFirst              = true;
524 
525             while (rsKeys.next()) {
526                String columnName = rsKeys.getString(4);
527                keys.addElement(columnName);
528 
529                if (isFirst) {
530                   defaultVisibleFields += columnName;
531                } else {
532                   defaultVisibleFields += ("," + columnName);
533                }
534 
535                isFirst = false;
536             }
537 
538             rsKeys.close();
539 
540             result.append(tableName)
541                   .append("\"");
542 
543             if (defaultVisibleFields.length() > 0) {
544                result.append("\n\t            defaultVisibleFields=\""
545                              + defaultVisibleFields + "\" ");
546             }
547 
548             result.append(">\n");
549 
550             // now try to get information about automatically 
551             // incemented fields. Unfortunaltely there is now 
552             // standard way to get this information in JDBC 2. 
553             // Is there one within JDBC 3 ? 
554             // 
555             if (checkForAutoIncFields) {
556                String sqlStmtPS = autoIncColumnsQuery;
557 
558                // We first construct a dbms specific query by substituting
559                // placeholders for catalog, schema and table name
560                // in a sql query. We do not use JDBC prepared queries
561                // with questionmarks because we do not know the order
562                // of these parameters and because '?' might not be allowed
563                // in any place
564                int pos = autoIncColumnsQuery.indexOf(tabnamePlaceholder);
565 
566                if (pos >= 0) {
567                   sqlStmtPS = autoIncColumnsQuery.substring(0, pos) + tableName
568                               + autoIncColumnsQuery.substring(pos
569                                                               + tabnamePlaceholder
570                                                                 .length());
571                }
572 
573                pos = sqlStmtPS.indexOf(schemaPlaceholder);
574 
575                if (pos >= 0) {
576                   sqlStmtPS = sqlStmtPS.substring(0, pos) + schemaName
577                               + sqlStmtPS.substring(pos
578                                                     + schemaPlaceholder.length());
579                }
580 
581                pos = sqlStmtPS.indexOf(catalogPlaceholder);
582 
583                if (pos >= 0) {
584                   sqlStmtPS = sqlStmtPS.substring(0, pos) + catalogName
585                               + sqlStmtPS.substring(pos
586                                                     + catalogPlaceholder.length());
587                }
588 
589                // now prepare statement having just one '?' for 
590                // column name left:
591                try { // if something goes wrong here (maybe wrong dbms version),
592                   spCall = con.prepareStatement(sqlStmtPS);
593                } catch (SQLException ex) {
594                   System.err.println("Warning: Prepare of Statement \n'"
595                                      + sqlStmtPS
596                                      + "'\n  failed with message \n'"
597                                      + ex.getMessage()
598                                      + "'.\n No reason to panic, just detection auf auto-incremented \n "
599                                      + " columns will not work. However, better send a mail to \n"
600                                      + " DbForms Mailing list to get this corrected");
601                }
602             }
603 
604             ResultSet rsFields = dbmd.getColumns(catalogName, schemaName,
605                                                  tableName, null);
606 
607             while (rsFields.next()) {
608                String columnName   = rsFields.getString(4);
609                String typeName     = rsFields.getString(6);
610                int    columnSize   = rsFields.getInt(7);
611                int    typeCode     = rsFields.getInt(5);
612                String defaultValue = null;
613 
614                if (generateDefaultValues) {
615                   defaultValue = rsFields.getString(13);
616 
617                   // don't bother keeping defaultValue if its "" or "0"
618                   if (defaultValue != null) {
619                      if (defaultValue.length() == 0) {
620                         defaultValue = null;
621                      } else if (defaultValue.equals("0")) {
622                         defaultValue = null;
623                      }
624                   }
625                }
626 
627                // programaticly change type for some special caes
628                typeName = remapType(dbms, typeName);
629 
630                // if we want to check for autoincremented
631                // columns and have successfully prepared a
632                // dbms specific query, we can now do an execute
633                // for this query and evaluate results:    
634                boolean isAutoIncColumn = false;
635 
636                if (checkForAutoIncFields && (spCall != null)) {
637                   try {
638                      spCall.setString(1, columnName);
639 
640                      ResultSet rssp = spCall.executeQuery();
641 
642                      switch (dbms) {
643                         case DBMS_MYSQL:
644                            isAutoIncColumn = (rssp.next()
645                                              && rssp.getString(1)
646                                                     .equalsIgnoreCase(columnName)
647                                              && rssp.getString(6)
648                                                     .equalsIgnoreCase("auto_increment"));
649 
650                            break;
651 
652                         case DBMS_IBMDB2:
653                            isAutoIncColumn = (rssp.next()
654                                              && rssp.getString(1)
655                                                     .equalsIgnoreCase("y"));
656 
657                            break;
658                      }
659 
660                      rssp.close();
661                   } catch (SQLException ex) {
662                      // We do not want to print out this message again and again for each column,
663                      // so we check if this error already occured and only print out message
664                      // the first time
665                      if (autoIncColumnsQueryAlwaysSucceeded) {
666                         System.err.println("Warning: Reading of auto-incremented columns  \n"
667                                            + "\n  failed with message \n'"
668                                            + ex.getMessage()
669                                            + "'.\n No reason to panic, just detection auf auto-incremented \n "
670                                            + " columns will not work. However, better send a mail to \n"
671                                            + " DbForms Mailing list to get this corrected");
672                         autoIncColumnsQueryAlwaysSucceeded = false;
673                      }
674                   }
675                } else { // some DBMS (like Sybase) simply have a trailing
676 
677                   // ' identity' in type name
678                   isAutoIncColumn = typeName.toLowerCase()
679                                             .endsWith(" identity");
680                }
681 
682                // if type name is unknown and user selected to
683                // generate standard type names in this case, try
684                // to set typeName to standard type name
685                if (useStdTypeNames && (!fieldTypeIsKnown(typeName))) {
686                   switch (typeCode) {
687                      case java.sql.Types.BIGINT:
688                      case java.sql.Types.INTEGER:
689                      case java.sql.Types.SMALLINT:
690                      case java.sql.Types.TINYINT:
691                         typeName = "integer";
692 
693                         break;
694 
695                      case java.sql.Types.CHAR:
696                         typeName = "char";
697                         break;
698                         
699                      case java.sql.Types.LONGVARCHAR:
700                         typeName = "long varchar";
701 
702                         break;
703                      case java.sql.Types.VARCHAR:
704                         typeName = "varchar";
705 
706                         break;
707 
708                      case java.sql.Types.DECIMAL:
709                         typeName = "decimal";
710 
711                         break;
712 
713                      case java.sql.Types.NUMERIC:
714                         typeName = "numeric";
715 
716                         break;
717 
718                      case java.sql.Types.FLOAT:
719                         typeName = "float";
720 
721                         break;
722 
723                      case java.sql.Types.REAL:
724                         typeName = "real";
725 
726                         break;
727 
728                      case java.sql.Types.DATE:
729                         typeName = "date";
730 
731                         break;
732 
733                      case java.sql.Types.TIMESTAMP:
734                         typeName = "timestamp";
735 
736                         break;
737 
738                      case java.sql.Types.BLOB:
739                         typeName = "blob";
740 
741                         break;
742 
743                      default:
744                         System.out.println("unknown java.sql.Type '" + typeName
745                                            + "'");
746                   }
747                }
748 
749                result.append("\t\t<field name=\"");
750                result.append(columnName);
751                result.append("\" fieldType=\"");
752                result.append(typeName.toLowerCase());
753                result.append("\" size=\"");
754                result.append(columnSize);
755                result.append("\"");
756 
757                if (keys.contains(columnName)) {
758                   result.append(" isKey=\"true\"");
759                }
760 
761                if (isAutoIncColumn) {
762                   result.append(" autoInc=\"true\"");
763                }
764 
765                if (generateDefaultValues && (defaultValue != null)) {
766                   result.append(" defaultValue=\"" + defaultValue + "\"");
767                }
768 
769                result.append("/>\n");
770             }
771 
772             rsFields.close();
773 
774             if (!useAutoCommitMode) {
775                con.commit();
776             }
777 
778             if (foreignKeyDetectionActivated) {
779                result.append(getForeignKeyTags(forKeys, catalogName,
780                                                schemaName, tableName));
781             }
782 
783             result.append("\n\t\t<!-- add \"granted-privileges\" element for security constraints -->\n\n\t</table>\n\n");
784          }
785 
786          if (catalogNameFailure > 0) {
787             showWarning = true;
788             warningMessage.append("<li> " + catalogNameFailure
789                                   + " empty catalog names not "
790                                   + "included in table name.");
791          }
792 
793          if (schemaNameFailure > 0) {
794             showWarning = true;
795             warningMessage.append("<li> " + schemaNameFailure
796                                   + " empty schema names not "
797                                   + "included in table name.");
798          }
799 
800          result.append("\t<!-- ========== Connection =================================== -->\n");
801          result.append("\t<!--\n");
802          result.append("\tuncomment this if you have access to JNDI of an application server (see users guide for more info)\n");
803          result.append("\t<dbconnection\n");
804          result.append("\t\tname = \"jdbc/dbformstest\"\n");
805          result.append("\t\tisJndi = \"true\"\n");
806          result.append("\t/>\n");
807          result.append("\t-->\n\n");
808 
809          result.append("\t<dbconnection\n");
810          result.append("\t\tname   = \"" + xmlClean(jdbcURL) + "\"\n");
811          result.append("\t\tisJndi = \"false\"\n");
812          result.append("\t\tconClass  = \"" + jdbcDriver + "\"\n");
813          result.append("\t\tusername = \"" + username + "\"\n");
814          result.append("\t\tpassword  = \"" + password + "\"\n");
815          result.append("\t/>\n");
816          result.append("</dbforms-config>");
817 
818          System.out.println("finished");
819          warningMessage.append("</ul></html>");
820       } catch (Exception e) {
821          e.printStackTrace();
822          throw new Exception(e.getMessage() + " in XMLConfigGenerator");
823       } finally {
824          try {
825             if (showWarning) {
826                if (createGuiMessagewindow) {
827                   javax.swing.JOptionPane.showMessageDialog(null,
828                                                             warningMessage,
829                                                             "Warning",
830                                                             javax.swing.JOptionPane.WARNING_MESSAGE);
831                } else {
832                   System.err.println("Warning:\n " + warningMessage);
833                }
834             }
835 
836             if (con != null) {
837                con.close();
838             }
839          } catch (SQLException sqle) {
840             // 20031130-HKK: Hint from Pavel Vesely; Ignore exception during close! 
841 
842             /*
843                throw new SQLException("could not close Connection - "
844                                       + sqle.getMessage());
845              */
846          }
847       }
848 
849       return result.toString();
850    }
851 
852 
853    /***
854     * DOCUMENT ME!
855     *
856     * @param jdbcDriver DOCUMENT ME!
857     * @param jdbcURL DOCUMENT ME!
858     * @param username DOCUMENT ME!
859     * @param password DOCUMENT ME!
860     *
861     * @return DOCUMENT ME!
862     *
863     * @throws SQLException DOCUMENT ME!
864     * @throws ClassNotFoundException DOCUMENT ME!
865     * @throws InstantiationException DOCUMENT ME!
866     * @throws IOException DOCUMENT ME!
867     * @throws IllegalAccessException DOCUMENT ME!
868     */
869    protected static Connection createConnection(String jdbcDriver,
870                                                 String jdbcURL,
871                                                 String username,
872                                                 String password)
873                                          throws SQLException, 
874                                                 ClassNotFoundException, 
875                                                 InstantiationException, 
876                                                 IllegalAccessException {
877       Class.forName(jdbcDriver)
878            .newInstance();
879 
880       return DriverManager.getConnection(jdbcURL, username, password);
881    }
882 
883 
884    static boolean fieldTypeIsKnown(String s) {
885       int i;
886 
887       for (i = 0; i < knownFieldTypes.length; i++)
888          if (s.startsWith(knownFieldTypes[i])) {
889             return true;
890          }
891 
892       return false;
893    }
894 
895 
896    private static void addSingleReference(HashMap   hm,
897                                           ResultSet rsk,
898                                           Vector    knownTables,
899                                           boolean   includeCatalog,
900                                           String    catalogSeparator,
901                                           boolean   includeSchema,
902                                           String    schemaSeparator)
903                                    throws SQLException {
904       String pCatalog = rsk.getString(1);
905       String pSchema = rsk.getString(2);
906       String pTable  = rsk.getString(3);
907 
908       if (!knownTables.contains("" + emptyIfNull(pSchema) + "\t"
909                                       + emptyIfNull(pTable))) {
910          return;
911       }
912 
913       String pColName = rsk.getString(4);
914 
915       String fSchema = rsk.getString(6);
916       String fTable  = rsk.getString(7);
917 
918       if (!knownTables.contains("" + emptyIfNull(fSchema) + "\t"
919                                       + emptyIfNull(fTable))) {
920          return;
921       }
922 
923       String fColName = rsk.getString(8);
924 
925       String fkName = rsk.getString(12);
926 
927       if (fkName == null) // foreign key name not set, construct one....
928        {
929          fkName = pCatalog + "::" + pSchema + "::" + pTable;
930       }
931 
932       String  hashKey = emptyIfNull(fSchema) + "\t" + fTable;
933 
934       HashMap tabForKeys = (HashMap) hm.get(hashKey); // Hash with foreign key information for referencing table
935 
936       if (tabForKeys == null) {
937          tabForKeys = new HashMap();
938          hm.put(hashKey, tabForKeys);
939       }
940 
941       ForeignKey fki = (ForeignKey) tabForKeys.get(fkName);
942 
943       if (fki == null) {
944          fki = new ForeignKey();
945          tabForKeys.put(fkName, fki);
946 
947          String fullTabName = "";
948 
949          if (includeCatalog) {
950             fullTabName = pCatalog + catalogSeparator;
951          }
952 
953          if (includeSchema) {
954             fullTabName += (pSchema + schemaSeparator);
955          }
956 
957          fullTabName += pTable;
958          fki.setForeignTable(fullTabName);
959          fki.setName(fkName);
960       }
961 
962       fki.addReference(new Reference(fColName, pColName));
963    }
964 
965 
966    private static String emptyIfNull(String s) {
967       return (s == null) ? ""
968                          : s;
969    }
970 
971 
972    /***
973     * DOCUMENT ME!
974     *
975     * @param dbms
976     * @param typeName
977     *
978     * @return
979     */
980    private static String remapType(int    dbms,
981                                    String typeName) {
982       if (dbms == DBMS_MYSQL) {
983          if (typeName.equalsIgnoreCase("longblob")) {
984             typeName = "blob";
985          }
986       }
987 
988       return typeName;
989    }
990 
991 
992    /***
993     * DOCUMENT ME!
994     *
995     * @param str
996     *
997     * @return
998     */
999    private static String xmlClean(String str) {
1000       return str.replaceAll("&", "&amp;");
1001    }
1002 }