001: /* Copyright 2002-2005 The Apache Software Foundation
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.apache.ojb.tools.mapping.reversedb2.dbmetatreemodel;
017:
018: import javax.swing.tree.TreeNode;
019: import org.apache.ojb.tools.mapping.reversedb2.propertyEditors.EditableTreeNodeWithProperties;
020:
021: /**
022: * Abstract implementation of a treenode representing an metadata object
023: * in a database. It implements loading the children of the node in a
024: * separate thread, thus not blocking the user interface.
025: * @author Administrator
026: */
027: public abstract class ReverseDbTreeNode extends
028: EditableTreeNodeWithProperties implements java.io.Serializable {
029: transient private java.sql.DatabaseMetaData dbMeta;
030: private DatabaseMetaDataTreeModel dbMetaTreeModel;
031:
032: /**
033: * List of children of this treenode.
034: */
035: protected java.util.ArrayList alChildren = new java.util.ArrayList();
036:
037: private boolean isFilled = false;
038:
039: transient private Object populationLock = new Object();
040: private boolean populationInProgress = false;
041:
042: private ReverseDbTreeNode parent = null;
043:
044: public ReverseDbTreeNode(java.sql.DatabaseMetaData pdbMeta,
045: DatabaseMetaDataTreeModel pdbMetaTreeModel,
046: ReverseDbTreeNode pparent) {
047: this .dbMeta = pdbMeta;
048: this .dbMetaTreeModel = pdbMetaTreeModel;
049: this .parent = pparent;
050: alChildren.add(new javax.swing.tree.DefaultMutableTreeNode(
051: "..."));
052: }
053:
054: /**
055: * @see TreeNode#getChildAt(int)
056: */
057: public TreeNode getChildAt(int index) {
058: if (!this .isFilled)
059: this .load(false, false, true);
060: return (TreeNode) this .alChildren.get(index);
061: }
062:
063: /**
064: * @see TreeNode#getChildCount()
065: */
066: public int getChildCount() {
067: return this .alChildren.size();
068: }
069:
070: /**
071: * @see TreeNode#getParent()
072: */
073: public TreeNode getParent() {
074: return this .parent;
075: }
076:
077: /**
078: * @see TreeNode#getIndex(TreeNode)
079: */
080: public int getIndex(TreeNode o) {
081: return this .alChildren.indexOf(o);
082: }
083:
084: /**
085: * @see TreeNode#getAllowsChildren()
086: */
087: public abstract boolean getAllowsChildren();
088:
089: /**
090: * @see TreeNode#isLeaf()
091: */
092: public abstract boolean isLeaf();
093:
094: /**
095: * @see TreeNode#children()
096: */
097: public java.util.Enumeration children() {
098: if (!this .isFilled)
099: this .load(false, false, true);
100: return java.util.Collections.enumeration(this .alChildren);
101: }
102:
103: /**
104: * Loads the children of this TreeNode. If another Thread is already active on this node the method returns
105: * without doing anything (if a separate Thread is started the method returns anyway, but the Thread might
106: * do nothing).
107: * @param recursive If true, all children down to the leaf node are retrieved
108: * @param replace If true the children are loaded unconditionally. If false the
109: * retrieval is only done if the node has not been populated before.
110: * @param inNewThread if true the load is done in a new thread.
111: */
112: public void load(final boolean recursive, final boolean replace,
113: final boolean inNewThread) {
114: if (inNewThread) {
115: new Thread() {
116: public void run() {
117: load(recursive, replace, false);
118: }
119: }.start();
120: return;
121: }
122: if (!populationInProgress) {
123: synchronized (this .populationLock) {
124: this .populationInProgress = true;
125: if (replace || !this .isFilled) {
126: this .isFilled = _load();
127: }
128: this .populationInProgress = false;
129: }
130: if (!recursive)
131: this .getDbMetaTreeModel().setStatusBarMessage("Done");
132: }
133: if (recursive) {
134: java.util.Enumeration e = this .children();
135: while (e.hasMoreElements()) {
136: Object o = e.nextElement();
137: if (o instanceof ReverseDbTreeNode)
138: ((ReverseDbTreeNode) o).load(recursive, replace,
139: false);
140: }
141: this .getDbMetaTreeModel().setStatusBarMessage("Done");
142: }
143: }
144:
145: /**
146: * Loads the children of this TreeNode. If the node is already populated, this method returns without action. If
147: * there is already a Thread populating this treenode the method waits until the other Thread has finished
148: * @param recursive if true, all children down to the leaf node are retrieved.
149: * @param replace if false and the list of children is already populated, return without action. If recursive
150: * is true, all children down to the leaf of the tree are checked.
151: */
152: public void loadWait(final boolean recursive,
153: final boolean replace, final boolean inNewThread) {
154: if (inNewThread) {
155: new Thread() {
156: public void run() {
157: loadWait(recursive, replace, false);
158: }
159: }.start();
160: return;
161: }
162:
163: synchronized (this .populationLock) {
164: this .populationInProgress = true;
165: if (replace || !this .isFilled) {
166: this .isFilled = _load();
167: }
168: if (recursive) {
169: java.util.Enumeration e = this .children();
170: while (e.hasMoreElements()) {
171: Object o = e.nextElement();
172: if (o instanceof ReverseDbTreeNode)
173: ((ReverseDbTreeNode) o).loadWait(recursive,
174: replace, false);
175: }
176: }
177: this .populationInProgress = false;
178: }
179: this .getDbMetaTreeModel().setStatusBarMessage("Done");
180: }
181:
182: /**
183: * Access method for the DatabaseMetaData object of this tree model
184: */
185: protected java.sql.DatabaseMetaData getDbMeta() {
186: return dbMeta;
187: }
188:
189: /**
190: * Access method for the TreeModel this node is associated to.
191: */
192: protected DatabaseMetaDataTreeModel getDbMetaTreeModel() {
193: return dbMetaTreeModel;
194: }
195:
196: /**
197: * Purpose of this method is to fill the children of the node. It should
198: * replace all children in alChildren (the arraylist containing the children)
199: * of this node and notify the TreeModel that a change has occurred.
200: */
201: protected abstract boolean _load();
202:
203: }
|