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