001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2009 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.gui; 012 013import org.apache.log4j.Logger; 014 015import java.sql.*; 016import java.util.*; 017import javax.swing.event.TreeModelListener; 018import javax.swing.tree.TreePath; 019 020/** 021 * 022 * @author sean 023 */ 024public class JdbcTreeModel implements javax.swing.tree.TreeModel { 025 026 private static final Logger LOGGER = Logger.getLogger(JdbcTreeModel.class); 027 028 private Vector treeModelListeners = new Vector(); 029 Connection connection; 030 DatabaseMetaData metadata; 031 List catalogs; 032 Node root; 033 034 /** Creates a new instance of JDBCTreeModel */ 035 public JdbcTreeModel(Connection c) { 036 connection = c; 037 try { 038 metadata = connection.getMetaData(); 039 catalogs = new ArrayList(); 040 String catalogName = connection.getCatalog(); 041 Node cat = new Node(catalogName, Node.CATALOG); 042 043 ResultSet trs = metadata.getTables(cat.name, null, null, null); 044 try { 045 while (trs.next()) { 046 // Oracle 10g Driver returns bogus BIN$ tables that cause 047 // exceptions 048 String tbname = trs.getString("TABLE_NAME"); 049 if (!tbname.matches("(?!BIN\\$).+")) { 050 continue; 051 } 052 053 Node table = new Node(trs.getString(3), Node.TABLE); 054 cat.children.add(table); 055 //get the tables for each catalog. 056 ResultSet crs = 057 metadata.getColumns(cat.name, null, table.name, null); 058 try { 059 while (crs.next()) { 060 Node column = 061 new Node(crs.getString(4), Node.COLUMN); 062 table.children.add(column); 063 } 064 } finally { 065 try { 066 if (crs != null) { 067 crs.close(); 068 } 069 } catch (Exception e) { 070 // ignore 071 } 072 } 073 } 074 } finally { 075 try { 076 if (trs != null) { 077 trs.close(); 078 } 079 } catch (Exception e) { 080 // ignore 081 } 082 } 083 root = cat; 084 } catch (Exception ex) { 085 LOGGER.error("JdbcTreeModel", ex); 086 } 087 } 088 089 090 /** Adds a listener for the <code>TreeModelEvent</code> 091 * posted after the tree changes. 092 * 093 * @param l the listener to add 094 * @see #removeTreeModelListener 095 * 096 */ 097 public void addTreeModelListener(TreeModelListener l) { 098 treeModelListeners.add(l); 099 } 100 101 /** Returns the child of <code>parent</code> at index <code>index</code> 102 * in the parent's 103 * child array. <code>parent</code> must be a node previously obtained 104 * from this data source. This should not return <code>null</code> 105 * if <code>index</code> 106 * is a valid index for <code>parent</code> (that is <code>index >= 0 && 107 * index < getChildCount(parent</code>)). 108 * 109 * @param parent a node in the tree, obtained from this data source 110 * @return the child of <code>parent</code> at index <code>index</code> 111 * 112 */ 113 public Object getChild(Object parent, int index) { 114 if (parent instanceof Node) { 115 return ((Node)parent).children.get(index); 116 } 117 118 return null; 119 } 120 121 /** Returns the number of children of <code>parent</code>. 122 * Returns 0 if the node 123 * is a leaf or if it has no children. <code>parent</code> must be a node 124 * previously obtained from this data source. 125 * 126 * @param parent a node in the tree, obtained from this data source 127 * @return the number of children of the node <code>parent</code> 128 * 129 */ 130 public int getChildCount(Object parent) { 131 if (parent instanceof Node) { 132 return ((Node)parent).children.size(); 133 } 134 return 0; 135 } 136 137 /** Returns the index of child in parent. If <code>parent</code> 138 * is <code>null</code> or <code>child</code> is <code>null</code>, 139 * returns -1. 140 * 141 * @param parent a note in the tree, obtained from this data source 142 * @param child the node we are interested in 143 * @return the index of the child in the parent, or -1 if either 144 * <code>child</code> or <code>parent</code> are <code>null</code> 145 * 146 */ 147 public int getIndexOfChild(Object parent, Object child) { 148 if (parent instanceof Node) { 149 return ((Node)parent).children.indexOf(child); 150 } 151 152 return -1; 153 } 154 155 /** Returns the root of the tree. Returns <code>null</code> 156 * only if the tree has no nodes. 157 * 158 * @return the root of the tree 159 * 160 */ 161 public Object getRoot() { 162 return root; 163 } 164 165 /** Returns <code>true</code> if <code>node</code> is a leaf. 166 * It is possible for this method to return <code>false</code> 167 * even if <code>node</code> has no children. 168 * A directory in a filesystem, for example, 169 * may contain no files; the node representing 170 * the directory is not a leaf, but it also has no children. 171 * 172 * @param node a node in the tree, obtained from this data source 173 * @return true if <code>node</code> is a leaf 174 * 175 */ 176 public boolean isLeaf(Object node) { 177 return getChildCount(node) == 0; 178 } 179 180 /** Removes a listener previously added with 181 * <code>addTreeModelListener</code>. 182 * 183 * @see #addTreeModelListener 184 * @param l the listener to remove 185 * 186 */ 187 public void removeTreeModelListener(TreeModelListener l) { 188 treeModelListeners.remove(l); 189 } 190 191 /** Messaged when the user has altered the value for the item identified 192 * by <code>path</code> to <code>newValue</code>. 193 * If <code>newValue</code> signifies a truly new value 194 * the model should post a <code>treeNodesChanged</code> event. 195 * 196 * @param path path to the node that the user has altered 197 * @param newValue the new value from the TreeCellEditor 198 * 199 */ 200 public void valueForPathChanged(TreePath path, Object newValue) { 201 } 202 203 class Node { 204 static final int CATALOG = 0; 205 static final int TABLE = 1; 206 static final int COLUMN = 2; 207 String name; 208 int type; 209 ArrayList children; 210 211 public Node(String n, int t) { 212 name = n; 213 type = t; 214 children = new ArrayList(); 215 } 216 217 public String toString() { 218 return name; 219 } 220 } 221} 222 223// End JdbcTreeModel.java