001: package net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree;
002:
003: /*
004: * Copyright (C) 2002-2004 Colin Bell and Johan Compagner
005: * colbell@users.sourceforge.net
006: * jcompagner@j-com.nl
007: *
008: * Modifications Copyright (c) 2004 Jason Height.
009: *
010: * This library is free software; you can redistribute it and/or
011: * modify it under the terms of the GNU Lesser General Public
012: * License as published by the Free Software Foundation; either
013: * version 2.1 of the License, or (at your option) any later version.
014: *
015: * This library is distributed in the hope that it will be useful,
016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018: * Lesser General Public License for more details.
019: *
020: * You should have received a copy of the GNU Lesser General Public
021: * License along with this library; if not, write to the Free Software
022: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
023: */
024: import java.io.Serializable;
025: import java.util.ArrayList;
026: import java.util.Comparator;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Set;
032: import java.util.TreeSet;
033:
034: import javax.swing.SwingUtilities;
035: import javax.swing.tree.DefaultTreeModel;
036: import javax.swing.tree.TreePath;
037:
038: import net.sourceforge.squirrel_sql.client.plugin.ISessionPlugin;
039: import net.sourceforge.squirrel_sql.client.plugin.PluginManager;
040: import net.sourceforge.squirrel_sql.client.plugin.SessionPluginInfo;
041: import net.sourceforge.squirrel_sql.client.session.ISession;
042: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.expanders.DatabaseExpander;
043: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.expanders.ProcedureTypeExpander;
044: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.expanders.TableTypeExpander;
045: import net.sourceforge.squirrel_sql.client.session.mainpanel.objecttree.expanders.UDTTypeExpander;
046: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
047: import net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectInfo;
048: import net.sourceforge.squirrel_sql.fw.sql.DatabaseObjectType;
049: import net.sourceforge.squirrel_sql.fw.sql.IDatabaseObjectInfo;
050: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
051: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
052:
053: /**
054: * This is the model for the object tree.
055: *
056: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
057: */
058: public class ObjectTreeModel extends DefaultTreeModel {
059: private static final long serialVersionUID = 1L;
060:
061: private static ILogger logger = LoggerController
062: .createLogger(ObjectTreeModel.class);
063:
064: /**
065: * Collection of <TT>INodeExpander</TT> objects. Each entry is a <TT>List</TT>
066: * of <TT>INodeExpander</TT> objects. The key to the list is the
067: * node type.
068: */
069: private Map<IIdentifier, List<INodeExpander>> _expanders = new HashMap<IIdentifier, List<INodeExpander>>();
070:
071: private final Set<DatabaseObjectType> _objectTypes = new TreeSet<DatabaseObjectType>(
072: new DatabaseObjectTypeComparator());
073:
074: /**
075: * ctor specifying session.
076: *
077: * @param session Current session.
078: *
079: * @throws IllegalArgumentException
080: * Thrown if <TT>null</TT> <TT>ISession</TT> passed.
081: */
082: public ObjectTreeModel(final ISession session) {
083: super (createRootNode(session), true);
084: if (session == null) {
085: throw new IllegalArgumentException("ISession == null");
086: }
087:
088: // Standard expanders.
089: session.getApplication().getThreadPool().addTask(
090: new Runnable() {
091: public void run() {
092: // must *not* be done in the GUI thread
093: final INodeExpander expander = new DatabaseExpander(
094: session);
095: SwingUtilities.invokeLater(new Runnable() {
096: public void run() {
097: // *must* be done in the GUI thread
098:
099: addExpander(DatabaseObjectType.CATALOG,
100: expander);
101: addExpander(DatabaseObjectType.SCHEMA,
102: expander);
103:
104: boolean foundTableExp = false;
105: boolean foundProcExp = false;
106: boolean foundUDTExp = false;
107: boolean foundDatabaseExp = false;
108: final PluginManager pmgr = session
109: .getApplication()
110: .getPluginManager();
111: for (Iterator<SessionPluginInfo> pluginItr = pmgr
112: .getSessionPluginIterator(); pluginItr
113: .hasNext();) {
114: ISessionPlugin p = (pluginItr
115: .next()).getSessionPlugin();
116: INodeExpander tableExp = p
117: .getDefaultNodeExpander(
118: session,
119: DatabaseObjectType.TABLE_TYPE_DBO);
120: if (tableExp != null) {
121: foundTableExp = true;
122: addExpander(
123: DatabaseObjectType.TABLE_TYPE_DBO,
124: tableExp);
125: }
126: INodeExpander procExp = p
127: .getDefaultNodeExpander(
128: session,
129: DatabaseObjectType.PROC_TYPE_DBO);
130: if (procExp != null) {
131: foundProcExp = true;
132: addExpander(
133: DatabaseObjectType.PROC_TYPE_DBO,
134: procExp);
135: }
136: INodeExpander udtExp = p
137: .getDefaultNodeExpander(
138: session,
139: DatabaseObjectType.UDT_TYPE_DBO);
140: if (udtExp != null) {
141: foundUDTExp = true;
142: addExpander(
143: DatabaseObjectType.UDT_TYPE_DBO,
144: udtExp);
145: }
146: INodeExpander databaseExp = p
147: .getDefaultNodeExpander(
148: session,
149: DatabaseObjectType.DATABASE_TYPE_DBO);
150: if (databaseExp != null) {
151: foundDatabaseExp = true;
152: addExpander(
153: DatabaseObjectType.SESSION,
154: databaseExp);
155: }
156: }
157:
158: if (!foundTableExp) {
159: addExpander(
160: DatabaseObjectType.TABLE_TYPE_DBO,
161: new TableTypeExpander());
162: }
163: if (!foundProcExp) {
164: addExpander(
165: DatabaseObjectType.PROC_TYPE_DBO,
166: new ProcedureTypeExpander());
167: }
168: if (!foundUDTExp) {
169: addExpander(
170: DatabaseObjectType.UDT_TYPE_DBO,
171: new UDTTypeExpander());
172: }
173: if (!foundDatabaseExp) {
174: addExpander(
175: DatabaseObjectType.SESSION,
176: expander);
177: }
178: reload();
179: }
180: });
181: }
182: });
183:
184: }
185:
186: /**
187: * Add an expander for the specified database object type in the
188: * object tree.
189: *
190: * @param dboType Database object type.
191: * @param expander Expander called to add children to a parent node.
192: *
193: * @throws IllegalArgumentException
194: * Thrown if a <TT>null</TT> <TT>INodeExpander</TT> or
195: * <TT>ObjectTreeNodeType</TT> passed.
196: */
197: public synchronized void addExpander(DatabaseObjectType dboType,
198: INodeExpander expander) {
199: if (dboType == null) {
200: throw new IllegalArgumentException(
201: "Null DatabaseObjectType passed");
202: }
203: if (expander == null) {
204: throw new IllegalArgumentException(
205: "Null INodeExpander passed");
206: }
207: getExpandersList(dboType).add(expander);
208: addKnownDatabaseObjectType(dboType);
209: }
210:
211: /**
212: * Return an array of the node expanders for the passed database object type.
213: *
214: * @param dboType Database object type.
215:
216: * @return an array of the node expanders for the passed database object type.
217: *
218: * @throws IllegalArgumentException
219: * Thrown if null ObjectTreeNodeType passed.
220: */
221: public synchronized INodeExpander[] getExpanders(
222: DatabaseObjectType dboType) {
223: if (dboType == null) {
224: throw new IllegalArgumentException(
225: "Null DatabaseObjectType passed");
226: }
227: List<INodeExpander> list = getExpandersList(dboType);
228: return list.toArray(new INodeExpander[list.size()]);
229: }
230:
231: /**
232: * Retrieve details about all object types that can be in this
233: * tree.
234: *
235: * @return DatabaseObjectType[] Array of object type info objects.
236: */
237: public synchronized DatabaseObjectType[] getDatabaseObjectTypes() {
238: DatabaseObjectType[] ar = new DatabaseObjectType[_objectTypes
239: .size()];
240: return _objectTypes.toArray(ar);
241: }
242:
243: synchronized void addKnownDatabaseObjectType(
244: DatabaseObjectType dboType) {
245: _objectTypes.add(dboType);
246: }
247:
248: /**
249: * Return the root node.
250: *
251: * @return the root node.
252: */
253: ObjectTreeNode getRootObjectTreeNode() {
254: return (ObjectTreeNode) getRoot();
255: }
256:
257: /**
258: * Get the collection of expanders for the passed node type. If one
259: * doesn't exist then create an empty one.
260: *
261: * @param dboType Database object type.
262: */
263: private List<INodeExpander> getExpandersList(
264: DatabaseObjectType dboType) {
265: if (dboType == null) {
266: throw new IllegalArgumentException(
267: "Null DatabaseObjectType passed");
268: }
269: IIdentifier key = dboType.getIdentifier();
270: List<INodeExpander> list = _expanders.get(key);
271: if (list == null) {
272: list = new ArrayList<INodeExpander>();
273: _expanders.put(key, list);
274: }
275: return list;
276: }
277:
278: /**
279: * Create the root node for this tree.
280: *
281: * @param session Current session.
282: *
283: * @throws IllegalArgumentException
284: * Thrown if <TT>null</TT> <TT>ISession</TT> passed.
285: */
286: private static ObjectTreeNode createRootNode(ISession session) {
287: if (session == null) {
288: throw new IllegalArgumentException("ISession == null");
289: }
290: return new RootNode(session);
291: }
292:
293: public TreePath getPathToDbInfo(String catalog, String schema,
294: String object, ObjectTreeNode startNode,
295: boolean useExpanders) {
296: if (dbObjectInfoEquals(catalog, schema, object, startNode
297: .getDatabaseObjectInfo())) {
298: return new TreePath(startNode.getPath());
299: } else {
300: if (useExpanders && 0 == startNode.getChildCount()) {
301: INodeExpander[] expanders = getExpanders(startNode
302: .getDatabaseObjectType());
303:
304: for (int i = 0; i < expanders.length; i++) {
305: try {
306: List<ObjectTreeNode> children = expanders[i]
307: .createChildren(startNode.getSession(),
308: startNode);
309:
310: for (int j = 0; j < children.size(); j++) {
311: ObjectTreeNode newChild = children.get(j);
312: if (0 == getExpanders(newChild
313: .getDatabaseObjectType()).length) {
314: newChild.setAllowsChildren(false);
315: } else {
316: newChild.setAllowsChildren(true);
317: }
318:
319: startNode.add(newChild);
320: }
321: } catch (Exception e) {
322: String msg = "Error loading object type "
323: + startNode.getDatabaseObjectType()
324: + ". Error: "
325: + e.toString()
326: + ". See SQuirreL Logs for stackttrace.";
327: startNode.getSession().showErrorMessage(msg);
328: logger.error(msg, e);
329: }
330: }
331: }
332:
333: for (int i = 0; i < startNode.getChildCount(); ++i) {
334: TreePath ret = getPathToDbInfo(catalog, schema, object,
335: (ObjectTreeNode) startNode.getChildAt(i),
336: useExpanders);
337: if (null != ret) {
338: return ret;
339: }
340: }
341: }
342: return null;
343: }
344:
345: private boolean dbObjectInfoEquals(String catalog, String schema,
346: String object, IDatabaseObjectInfo doi) {
347: if (null != catalog) {
348: if (false == catalog.equalsIgnoreCase(doi.getCatalogName())) {
349: return false;
350: }
351: }
352:
353: if (null != schema) {
354: if (false == schema.equalsIgnoreCase(doi.getSchemaName())) {
355: return false;
356: }
357: }
358:
359: if (null != object) {
360: if (false == object.equalsIgnoreCase(doi.getSimpleName())
361: && false == object.equalsIgnoreCase(doi
362: .getQualifiedName())) {
363: return false;
364: }
365: }
366:
367: return true;
368: }
369:
370: public boolean isRootNode(Object node) {
371: return node instanceof RootNode;
372: }
373:
374: private static final class RootNode extends ObjectTreeNode {
375: private static final long serialVersionUID = 1L;
376:
377: RootNode(ISession session) {
378: super (session, createDbo(session));
379: }
380:
381: private static final IDatabaseObjectInfo createDbo(
382: ISession session) {
383: return new DatabaseObjectInfo(null, null, session
384: .getAlias().getName(), DatabaseObjectType.SESSION,
385: session.getMetaData());
386: }
387: }
388:
389: private static final class DatabaseObjectTypeComparator implements
390: Comparator<DatabaseObjectType>, Serializable {
391: private static final long serialVersionUID = 1L;
392:
393: public int compare(DatabaseObjectType o1, DatabaseObjectType o2) {
394: return o1.getName().compareToIgnoreCase(o2.getName());
395: }
396: }
397: }
|