View Javadoc

1   /*   Copyright (C) 2003 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   */
17  
18  package com.finalist.jaggenerator;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Collections;
27  import java.sql.Connection;
28  import java.sql.ResultSet;
29  import java.sql.SQLException;
30  import java.sql.DatabaseMetaData;
31  
32  /***
33   * This class is a refactoring mid-step.  The original code contained duplicate methods for database access
34   * in different classes - I've rehoused them here.
35   *
36   * @author Michael O'Connor, Rudie Ekkelenkamp - Finalist IT Group
37   */
38  public class DatabaseUtils {
39     static Log log = LogFactory.getLog(DatabaseUtils.class);
40  
41     //a map of table name (String) --> ArrayList of Column objects.
42     private static final HashMap columnsCache = new HashMap();
43  
44     //a list of table names (String)
45     private static ArrayList tablesCache;
46  
47     //I think this can be refactored out, once getPrimaryKeys() reference in JagGenerator is removed..
48     private static final HashMap pkCache = new HashMap();
49     private static final String TABLE_NAME = "TABLE_NAME";
50     private static final String[] DEFAULT_TABLE_TYPES = new String[]{"TABLE"};
51  
52  
53     /***
54      * Gets all columns in the specified table, setting up a database connection if one isn't already available.
55      *
56      * @param tablename the name of the table.
57      * @return an ArrayList of Column objects for all columns in the specified table,
58      *         or <code>null</code> if the table/column doesn't exist.
59      */
60     public static ArrayList getColumns(String tablename) {
61        return getColumns(tablename, true);
62     }
63  
64     /***
65      * Gets all columns in the specified table.
66      *
67      * @param tablename       the name of the table.
68      * @param forceConnection set to <code>true</code> if this method should force a database connect,
69      *                        if not already connected.
70      * @return an ArrayList of Column objects for all columns in the specified table;
71      *         or <code>null</code> if the table/column doesn't exist, or if no database connection was available and
72      *         <code>forceConnection</code> was set to <code>false</code>.
73      */
74     public static ArrayList getColumns(String tablename, boolean forceConnection) {
75        if (columnsCache.get(tablename) != null) {
76           return (ArrayList) columnsCache.get(tablename);
77        }
78  
79        if (!forceConnection && JagGenerator.getConManager() == null) {
80           return null;
81        }
82        ArrayList pkeys = getPrimaryKeys(tablename);
83        GenericJdbcManager conManager = JagGenerator.getConManager();
84        Connection con = null;
85        ArrayList list = new ArrayList();
86        try {
87           con = conManager.connect();
88           DatabaseMetaData meta = con.getMetaData();
89           ResultSet columns = meta.getColumns(null, conManager.getSchema(), tablename, "%");
90           Column c = null;
91           while (columns.next()) {
92              c = new Column();
93              switch (columns.getInt("NULLABLE")) {
94                 case DatabaseMetaData.columnNullable:
95                    c.setNullable(true);
96                    break;
97                 case DatabaseMetaData.columnNoNulls:
98                    c.setNullable(false);
99                    break;
100                case DatabaseMetaData.columnNullableUnknown:
101                   c.setNullable(false);
102                default:
103                   c.setNullable(true);
104             }
105 
106             c.setName(columns.getString("COLUMN_NAME"));
107             if (pkeys.contains(columns.getString("COLUMN_NAME"))) {
108                c.setPrimaryKey(true);
109             } else {
110                c.setPrimaryKey(false);
111             }
112 
113             c.setLength(columns.getInt("COLUMN_SIZE"));
114             c.setPrecision(columns.getInt("COLUMN_SIZE"));
115             c.setScale(columns.getInt("DECIMAL_DIGITS"));
116             c.setSqlType(columns.getString("TYPE_NAME"));
117             list.add(c);
118          }
119          columns.close();
120 
121       } catch (Exception e) {
122          e.printStackTrace();
123       } finally {
124          if (con != null) {
125             try {
126                con.close();
127             } catch (SQLException e) {
128             }
129          }
130       }
131 
132       columnsCache.put(tablename, list);
133       return list;
134    }
135 
136    /***
137     * Gets information about any foreign keys that are imported into the specified table.
138     *
139     * @param tablename
140     * @return a List of ForeignKey objects, never <code>null</code>..
141     */
142    public static List getForeignKeys(String tablename) {
143       log.debug("Get the foreign keys for table: " + tablename);
144       ArrayList fkeys = new ArrayList();
145       GenericJdbcManager conManager = JagGenerator.getConManager();
146       if (conManager == null) {
147          JagGenerator.logToConsole("Can't retrieve foreign keys - no database connection!");
148       } else {
149          Connection con = null;
150          try {
151             con = conManager.connect();
152             ResultSet foreignKeys = con.getMetaData().getImportedKeys("", conManager.getSchema(), tablename);
153 
154             while (foreignKeys.next()) {
155                ForeignKey fk = new ForeignKey();
156                try {
157                   fk.setPkTableCat(foreignKeys.getString("PKTABLE_CAT"));
158                } catch (Exception e) {
159                   // Ignore, in case the JDBC driver doesn't support this propery.
160                }
161                try {
162                   fk.setPkTableSchem(foreignKeys.getString("PKTABLE_SCHEM"));
163                } catch (Exception e) {
164                   // Ignore, in case the JDBC driver doesn't support this propery.
165                }
166                try {
167                   fk.setPkTableName(foreignKeys.getString("PKTABLE_NAME"));
168                } catch (Exception e) {
169                   // Ignore, in case the JDBC driver doesn't support this propery.
170                }
171                try {
172 
173                   fk.setPkColumnName(foreignKeys.getString("PKCOLUMN_NAME"));
174                } catch (Exception e) {
175                   // Ignore, in case the JDBC driver doesn't support this propery.
176                }
177                try {
178                   fk.setFkTableCat(foreignKeys.getString("FKTABLE_CAT"));
179                } catch (Exception e) {
180                   // Ignore, in case the JDBC driver doesn't support this propery.
181                }
182                try {
183 
184                   fk.setFkTableSchem(foreignKeys.getString("FKTABLE_SCHEM"));
185                } catch (Exception e) {
186                   // Ignore, in case the JDBC driver doesn't support this propery.
187                }
188                try {
189 
190                   fk.setFkTableName(foreignKeys.getString("FKTABLE_NAME"));
191                } catch (Exception e) {
192                   // Ignore, in case the JDBC driver doesn't support this propery.
193                }
194                try {
195 
196                   fk.setFkColumnName(foreignKeys.getString("FKCOLUMN_NAME"));
197                } catch (Exception e) {
198                   // Ignore, in case the JDBC driver doesn't support this propery.
199                }
200                try {
201 
202                   fk.setKeySeq(foreignKeys.getShort("KEY_SEQ"));
203                } catch (Exception e) {
204                   // Ignore, in case the JDBC driver doesn't support this propery.
205                }
206                try {
207                   fk.setUpdateRule(foreignKeys.getShort("UPDATE_RULE"));
208                } catch (Exception e) {
209                   // Ignore, in case the JDBC driver doesn't support this propery.
210                }
211                try {
212 
213                   fk.setDeleteRule(foreignKeys.getShort("DELETE_RULE"));
214                } catch (Exception e) {
215                   // Ignore, in case the JDBC driver doesn't support this propery.
216                }
217                try {
218 
219                   fk.setPkName(foreignKeys.getString("PK_NAME"));
220                } catch (Exception e) {
221                   // Ignore, in case the JDBC driver doesn't support this propery.
222                }
223                try {
224 
225                   fk.setDeferrability(foreignKeys.getShort("DEFERRABILITY"));
226                } catch (Exception e) {
227                   // Ignore, in case the JDBC driver doesn't support this propery.
228                }
229                // Log the tables and columns from which relations are generated.
230                log.debug("Foreign key table and column name: " + fk.getFkTableName() + " - " + fk.getFkColumnName());
231                log.debug("foreign table and pk column name: " + fk.getPkTableName() + " - " + fk.getPkColumnName());
232 
233                // Since the fk name is not set, we use the column name to set it.s
234                fk.setFkName(Utils.format(fk.getFkColumnName()));
235                fkeys.add(fk);
236             }
237          } catch (Exception e) {
238             e.printStackTrace();
239          } finally {
240             if (con != null) {
241                try {
242                   con.close();
243                } catch (SQLException e) {
244                }
245             }
246          }
247       }
248 
249       return fkeys;
250    }
251 
252    /***
253     * A list with Strings of all primary key fields.
254     *
255     * @param tablename
256     * @return an ArrayList of primary key column names for the specified table, never <code>null</code>.
257     * @todo make this private - all primary key work should be done in this class.
258     */
259    public static ArrayList getPrimaryKeys(String tablename) {
260       if (pkCache.get(tablename) != null) {
261          return (ArrayList) pkCache.get(tablename);
262       }
263       GenericJdbcManager conManager = JagGenerator.getConManager();
264       Connection con = null;
265       ArrayList pkeys = new ArrayList();
266       try {
267          con = conManager.connect();
268          ResultSet r = con.getMetaData().getPrimaryKeys(null, conManager.getSchema(), tablename);
269          while (r.next()) {
270             pkeys.add(r.getString("COLUMN_NAME"));
271          }
272       } catch (Exception e) {
273          e.printStackTrace();
274       } finally {
275          if (con != null) {
276             try {
277                con.close();
278             } catch (SQLException e) {
279             }
280          }
281       }
282 
283       pkCache.put(tablename, pkeys);
284       return pkeys;
285    }
286 
287    /***
288     * Grabs the list of tables from the database.
289     *
290     * @return a List of table names (String), never <code>null</code>.
291     */
292    public static ArrayList getTables() {
293       if (tablesCache == null) {
294          tablesCache = new ArrayList();
295          GenericJdbcManager conManager = JagGenerator.getConManager();
296          String[] displayTableTypes = conManager.getDisplayTableTypes();
297          if (displayTableTypes == null) {
298             displayTableTypes = DEFAULT_TABLE_TYPES;
299          }
300          ResultSet tables = null;
301          Connection con = null;
302          try {
303             con = conManager.connect();
304             // Look for tables of the type table, not for synonyms: ,"SYNONYM"
305             ResultSet schemas = con.getMetaData().getSchemas();
306             while (schemas.next()) {
307                Object o = schemas.getObject(1);
308                System.out.println("schema:" + o);
309             }
310 
311             tables = con.getMetaData().getTables(null, conManager.getSchema(), "%", displayTableTypes);
312 
313             while (tables.next()) {
314                // Iterate over the tablenames and get the tablenames.
315                String tableName = tables.getString(TABLE_NAME);
316                if (tableName != null) {
317                   tablesCache.add(tableName);
318                }
319             }
320          } catch (Exception e) {
321             e.printStackTrace();
322             JagGenerator.logToConsole("Error getting tables list: " + e.toString());
323 
324          } finally {
325 
326             if (tables != null)
327                try {
328                   tables.close();
329                } catch (Exception e) {
330                }
331 
332             if (con != null)
333                try {
334                   con.close();
335                } catch (SQLException e) {
336                }
337          }
338       }
339       if (tablesCache != null)
340          Collections.sort(tablesCache);
341       return tablesCache;
342    }
343 
344    /***
345     * This needs to be called when databases are switched.
346     */
347    public static void clearCache() {
348       tablesCache = null;
349    }
350 
351    /***
352     * Forces an update of a particular table's columns the next time they are required.
353     *
354     * @param tableName
355     */
356    public static void clearColumnsCacheForTable(String tableName) {
357       columnsCache.remove(tableName);
358    }
359 
360 }