001 /* JAPI - (Yet another (hopefully) useful) Java API 002 * 003 * Copyright (C) 2004-2006 Christian Hujer 004 * 005 * This program is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU General Public License as 007 * published by the Free Software Foundation; either version 2 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, but 011 * WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program; if not, write to the Free Software 017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 018 * 02111-1307, USA. 019 */ 020 021 package net.sf.japi.sql; 022 023 import java.sql.SQLException; 024 import java.sql.DatabaseMetaData; 025 import java.sql.ResultSet; 026 import java.util.ArrayList; 027 import java.util.List; 028 import javax.swing.event.EventListenerList; 029 import javax.swing.event.TreeModelListener; 030 import javax.swing.event.TreeModelEvent; 031 import javax.swing.tree.TreePath; 032 import javax.swing.tree.TreeModel; 033 034 /** A TreeModel displaying the catalogs of a database (usually tables and views) as tree. 035 * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a> 036 */ 037 @SuppressWarnings({"ObjectEquality"}) 038 public class DatabaseTreeModel implements TreeModel { 039 040 /** The event listeners. */ 041 private EventListenerList listenerList = new EventListenerList(); 042 043 /** The Database nodes in the tree. */ 044 private List<CatalogTreeNode> catalogs = new ArrayList<CatalogTreeNode>(); 045 046 /** The Database Metadata of the database this treemodel reflects. */ 047 private DatabaseMetaData databaseMetaData; 048 049 /** Create a DatabaseTreeModel. 050 * Thw tree model is not yet connected to databaseMetaData. 051 */ 052 public DatabaseTreeModel() { 053 } 054 055 /** Create a DatabaseTreeModel for a Database. 056 * @param databaseMetaData Database Metadata for this tree model 057 * @throws SQLException in case of database problems 058 */ 059 public DatabaseTreeModel(final DatabaseMetaData databaseMetaData) throws SQLException { 060 this.databaseMetaData = databaseMetaData; 061 refresh(); 062 } 063 064 /** Refresh the data of this model from the database. 065 * @throws SQLException in case of database problems 066 */ 067 public void refresh() throws SQLException { 068 catalogs.clear(); 069 if (databaseMetaData != null) { 070 ResultSet rs = null; 071 try { 072 rs = databaseMetaData.getCatalogs(); 073 while (rs.next()) { 074 try { 075 catalogs.add(new CatalogTreeNode(rs.getString(1))); 076 } catch (final SQLException e) { 077 System.err.println(e); 078 // TODO 079 } 080 } 081 } finally { 082 try { rs.close(); } catch (final Exception e) { /* ignore **/ } finally { rs = null; } 083 } 084 } 085 fireTreeStructureChanged(); 086 } 087 088 /** Set the databaseMetaData for this model. 089 * @param databaseMetaData database meta data for this model 090 * @throws SQLException in case of database problems 091 */ 092 public void setDatabaseMetaData(final DatabaseMetaData databaseMetaData) throws SQLException { 093 this.databaseMetaData = databaseMetaData; 094 refresh(); 095 } 096 097 /** Get the databaseMetaData of this model. 098 * @return databaseMetaData of this model 099 */ 100 public DatabaseMetaData getDatabaseMetaData() { 101 return databaseMetaData; 102 } 103 104 /** {@inheritDoc} */ 105 public void addTreeModelListener(final TreeModelListener l) { 106 listenerList.add(TreeModelListener.class, l); 107 } 108 109 /** {@inheritDoc} */ 110 public Object getChild(final Object parent, final int index) { 111 if (parent == this) { 112 return catalogs.get(index); 113 } else { 114 assert parent instanceof CatalogTreeNode; 115 return ((CatalogTreeNode) parent).getTable(index); 116 } 117 } 118 119 /** {@inheritDoc} */ 120 public int getChildCount(final Object parent) { 121 if (parent == this) { 122 return catalogs.size(); 123 } else { 124 return ((CatalogTreeNode) parent).getTableCount(); 125 } 126 } 127 128 /** {@inheritDoc} */ 129 public int getIndexOfChild(final Object parent, final Object child) { 130 if (parent == this) { 131 return catalogs.indexOf(child); 132 } else { 133 return ((CatalogTreeNode) parent).getTableIndex((CatalogTreeNode.TableTreeNode) child); 134 } 135 } 136 137 /** {@inheritDoc} */ 138 public Object getRoot() { 139 return this; 140 } 141 142 /** {@inheritDoc} */ 143 public boolean isLeaf(final Object node) { 144 return node instanceof CatalogTreeNode.TableTreeNode; 145 } 146 147 /** {@inheritDoc} */ 148 public void removeTreeModelListener(final TreeModelListener l) { 149 listenerList.remove(TreeModelListener.class, l); 150 } 151 152 /** {@inheritDoc} */ 153 public void valueForPathChanged(final TreePath path, final Object newValue) { 154 } 155 156 /** Event fire if the tree has changed. */ 157 private void fireTreeStructureChanged() { 158 TreeModelEvent e = null; 159 final Object[] listeners = listenerList.getListenerList(); 160 for (int i = listeners.length - 2; i >= 0; i -= 2) { 161 if (listeners[i] == TreeModelListener.class) { 162 if (e == null) { 163 e = new TreeModelEvent(this, new Object[] { this }); 164 } 165 ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e); 166 } 167 } 168 } 169 170 /** A TreeNode reflecting a Database. */ 171 public class CatalogTreeNode { 172 173 /** The name of this catalog. */ 174 private String catalog; 175 176 /** The tables of this catalog. */ 177 private List<TableTreeNode> tables = new ArrayList<TableTreeNode>(); 178 179 /** Create a CatalogTreeNode. 180 * @throws SQLException in case of database problems 181 */ 182 CatalogTreeNode(final String catalog) throws SQLException { 183 this.catalog = catalog; 184 ResultSet rs = null; 185 try { 186 rs = databaseMetaData.getTables(catalog, null, null, null); 187 while (rs.next()) { 188 tables.add(new TableTreeNode(rs.getString("TABLE_NAME"))); 189 } 190 } finally { 191 try { rs.close(); } catch (final Exception e) { /* ignore **/ } finally { rs = null; } 192 } 193 } 194 195 /** Get a table with a certain index. 196 * @param index index of table to get 197 * @return table for <var>index</var> 198 */ 199 TableTreeNode getTable(final int index) { 200 return tables.get(index); 201 } 202 203 /** Get the number of tables. 204 * @return number of tables 205 */ 206 public int getTableCount() { 207 return tables.size(); 208 } 209 210 /** Get the index of a table. 211 * @param table Table to get index of 212 * @return index of <var>table</var> 213 */ 214 public int getTableIndex(final TableTreeNode table) { 215 return tables.indexOf(table); 216 } 217 218 /** {@inheritDoc} */ 219 @Override public String toString() { 220 return catalog; 221 } 222 223 /** A TreeNode reflecting a Table. */ 224 public class TableTreeNode { 225 226 /** The name of this table. */ 227 private String table; 228 229 /** Create a TableTreeNode. */ 230 TableTreeNode(final String table) { 231 this.table = table; 232 } 233 234 /** Get the name of the table this TableTreeNode represents. 235 * @return table name 236 */ 237 public String getTableName() { 238 return catalog + '.' + table; 239 } 240 241 /** Get the name of the catalog this TableTreeNode is in. 242 * @return catalog name 243 */ 244 public String getCatalogName() { 245 return catalog; 246 } 247 248 /** {@inheritDoc} */ 249 @Override public String toString() { 250 return table; 251 } 252 253 } // class TableTreeNode 254 255 } // class CatalogTreeNode 256 257 } // class DatabaseTreeModel