001: /*
002: * DependencyNode.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.db;
013:
014: import java.util.ArrayList;
015: import java.util.Collections;
016: import java.util.HashMap;
017: import java.util.HashSet;
018: import java.util.List;
019: import java.util.Map;
020: import java.util.Set;
021: import workbench.util.StringUtil;
022:
023: /**
024: * A node in the dependency tree for a table
025: *
026: * @see workbench.db.TableDependency
027: * @see workbench.db.DeleteScriptGenerator
028: * @see workbench.db.importer.TableDependencySorter
029: */
030: public class DependencyNode {
031: private DependencyNode parentNode;
032: private TableIdentifier table;
033: private String updateAction = "";
034: private String deleteAction = "";
035: private String fkName;
036:
037: /**
038: * Maps the columns of the base table (this.table) to the matching column
039: * of the parent table (parentNode.getTable())
040: */
041: private HashMap<String, String> columns = new HashMap<String, String>();
042:
043: private ArrayList<DependencyNode> childTables = new ArrayList<DependencyNode>();
044:
045: public DependencyNode(TableIdentifier aTable) {
046: this .table = aTable.createCopy();
047: this .parentNode = null;
048: }
049:
050: public void addColumnDefinition(String aColumn, String aParentColumn) {
051: Object currentParent = this .columns.get(aColumn);
052: if (currentParent == null) {
053: this .columns.put(aColumn, aParentColumn);
054: }
055: }
056:
057: /**
058: * Returns the level of this node in the dependency hierarchy.
059: * @return 0 if no parent is available (i.e. the root of the tree)
060: * -1 if this is a self referencing dependency
061: */
062: public int getLevel() {
063: if (parentNode == null)
064: return 0;
065: if (parentNode == this )
066: return -1;
067: return 1 + parentNode.getLevel();
068: }
069:
070: public void setParent(DependencyNode aParent, String aFkName) {
071: if (aFkName == null)
072: throw new NullPointerException("FK Name may not be null");
073: this .parentNode = aParent;
074: this .fkName = aFkName;
075: }
076:
077: public String toString() {
078: if (this .fkName == null) {
079: return this .table.getTableName();
080: } else {
081: return this .table.getTableName() + " (" + this .fkName + ")";
082: }
083: }
084:
085: public String getFkName() {
086: return this .fkName;
087: }
088:
089: public TableIdentifier getParentTable() {
090: if (parentNode == null)
091: return null;
092: return this .parentNode.getTable();
093: }
094:
095: public TableIdentifier getTable() {
096: return this .table;
097: }
098:
099: /**
100: * Returns a Map that maps the columns of the base table to the matching column
101: * of the related (parent/child) table.
102: *
103: * The keys to the map are columns from this node's table {@link #getTable()}
104: * The values in this map are columns found in this node's "parent" table
105: *
106: * @see #getTable()
107: * @see #getParentTable()
108: */
109: public Map<String, String> getColumns() {
110: if (this .columns == null) {
111: return Collections.emptyMap();
112: } else {
113: return this .columns;
114: }
115: }
116:
117: /**
118: * Checks if this node defines the foreign key constraint name aFkname
119: * to the given table
120: */
121: public boolean isDefinitionFor(TableIdentifier tbl, String aFkname) {
122: if (aFkname == null)
123: return false;
124: return this .table.equals(tbl) && aFkname.equals(this .fkName);
125: }
126:
127: public boolean equals(Object other) {
128: if (other instanceof DependencyNode) {
129: DependencyNode node = (DependencyNode) other;
130: return this .isDefinitionFor(node.getTable(), node
131: .getFkName());
132: }
133: return false;
134: }
135:
136: public int hashCode() {
137: StringBuilder sb = new StringBuilder(60);
138: sb.append(this .table.getTableExpression() + "-" + this .fkName);
139: return StringUtil.hashCode(sb);
140: }
141:
142: public boolean isRoot() {
143: return this .parentNode == null;
144: }
145:
146: public DependencyNode getParent() {
147: return this .parentNode;
148: }
149:
150: public List<DependencyNode> getChildren() {
151: return this .childTables;
152: }
153:
154: /**
155: * Recursively finds a DependencyNode in the tree of nodes
156: */
157: public DependencyNode findNode(DependencyNode toFind) {
158: if (toFind == null)
159: return null;
160: if (toFind.equals(this ))
161: return this ;
162: for (DependencyNode node : childTables) {
163: if (toFind.equals(node)) {
164: return node;
165: } else {
166: DependencyNode n = node.findNode(toFind);
167: if (n != null)
168: return n;
169: }
170: }
171: return null;
172: }
173:
174: public DependencyNode addChild(TableIdentifier table, String aFkname) {
175: if (aFkname == null)
176: throw new NullPointerException("FK Name may not be null");
177: for (DependencyNode node : childTables) {
178: if (node.isDefinitionFor(table, aFkname)) {
179: return node;
180: }
181: }
182: DependencyNode node = new DependencyNode(table);
183: node.setParent(this , aFkname);
184: this .childTables.add(node);
185: return node;
186: }
187:
188: public boolean containsChild(DependencyNode aNode) {
189: if (aNode == null)
190: return false;
191: return this .childTables.contains(aNode);
192: }
193:
194: public boolean addChild(DependencyNode aTable) {
195: if (this .containsChild(aTable))
196: return false;
197: this .childTables.add(aTable);
198: return true;
199: }
200:
201: public String getDeleteAction() {
202: return this .deleteAction;
203: }
204:
205: public void setDeleteAction(String anAction) {
206: this .deleteAction = anAction;
207: }
208:
209: public String getUpdateAction() {
210: return this .updateAction;
211: }
212:
213: public void setUpdateAction(String anAction) {
214: this .updateAction = anAction;
215: }
216:
217: public void printAll() {
218: int level = getLevel();
219: StringBuilder indent = new StringBuilder(level * 2);
220: for (int i = 0; i < level; i++)
221: indent.append(" ");
222:
223: System.out.println(indent + toString());
224: for (DependencyNode node : childTables) {
225: node.printAll();
226: }
227: }
228: }
|