KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > sql > schema > DatabaseTable


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Copyright (C) 2005-2006 Continuent, Inc.
7  * Contact: sequoia@continuent.org
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Mathieu Peltier, Sara Bouchenak.
23  */

24
25 package org.continuent.sequoia.controller.sql.schema;
26
27 import java.io.Serializable JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Iterator JavaDoc;
31
32 import org.continuent.sequoia.controller.locks.TransactionLogicalLock;
33
34 /**
35  * A <code>DatabaseTable</code> represents a database table ! It is just an
36  * array of <code>TableColumns</code> objects.
37  * <p>
38  * Keep it mind that <code>ArrayList</code> is not synchronized...
39  *
40  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet</a>
41  * @author <a HREF="mailto:Mathieu.Peltier@inrialpes.fr">Mathieu Peltier</a>
42  * @author <a HREF="mailto:Sara.Bouchenak@epfl.ch">Sara Bouchenak</a>
43  * @version 1.0
44  */

45 public class DatabaseTable implements Serializable JavaDoc
46 {
47   private static final long serialVersionUID = 7138810420058450235L;
48
49   /** Schema name this table belongs to */
50   private String JavaDoc schema;
51
52   /** Database table name. */
53   private String JavaDoc name;
54
55   /** <code>ArrayList</code> of <code>DatabaseColumn</code>. */
56   private ArrayList JavaDoc columns;
57
58   /** Lock for this table */
59   private transient TransactionLogicalLock lock = new TransactionLogicalLock();
60
61   /**
62    * List of tables that must be locked when this table is updated. This is
63    * usually the list of tables that have a foreign key referencing this table.<br>
64    * <code>ArrayList</code> of <code>String</code> (table names)
65    */

66   private ArrayList JavaDoc dependingTables;
67
68   /**
69    * Creates a new <code>DatabaseTable</code> instance.
70    *
71    * @param name table name
72    */

73   public DatabaseTable(String JavaDoc name)
74   {
75     this(name, new ArrayList JavaDoc());
76   }
77
78   /**
79    * Creates a new <code>DatabaseTable</code> instance.
80    *
81    * @param name table name
82    * @param nbOfColumns number of columns
83    */

84   public DatabaseTable(String JavaDoc name, int nbOfColumns)
85   {
86     this(name, new ArrayList JavaDoc(nbOfColumns));
87   }
88
89   /**
90    * Creates a new <code>DatabaseTable</code> instance. New table shares
91    * (only) its name and columns with the table passed as parameter.
92    *
93    * @param dt database table
94    */

95   public DatabaseTable(DatabaseTable dt)
96   {
97     this(dt.getName(), dt.getColumns());
98     if (dt.getDependingTables() != null)
99       for (Iterator JavaDoc i = dt.getDependingTables().iterator(); i.hasNext();)
100         addDependingTable((String JavaDoc) i.next());
101   }
102
103   /**
104    * Creates a new <code>DatabaseTable</code> instance.
105    *
106    * @param name table name
107    * @param columns columns list
108    */

109   private DatabaseTable(String JavaDoc name, ArrayList JavaDoc columns)
110   {
111     if (name == null)
112       throw new IllegalArgumentException JavaDoc(
113           "Illegal null database table name in DatabaseTable constructor");
114
115     this.name = name;
116     this.columns = columns;
117   }
118
119   /**
120    * Add a depending table to this table. A depending table is locked when the
121    * current table is updated. A depending table is usually a table that has a
122    * foreign key referencing the current table.<br>
123    * This method takes care of duplicates and a table name is only inserted
124    * once.
125    *
126    * @param tableName the depending table to add
127    */

128   public synchronized void addDependingTable(String JavaDoc tableName)
129   {
130     if (dependingTables == null)
131       dependingTables = new ArrayList JavaDoc();
132     if (!dependingTables.contains(tableName))
133       dependingTables.add(tableName);
134   }
135
136   /**
137    * Adds a <code>DatabaseColumn</code> object to this table.
138    * <p>
139    * Warning! The underlying <code>ArrayList</code> is not synchronized.
140    *
141    * @param column a <code>DatabaseColumn</code> value
142    */

143   public void addColumn(DatabaseColumn column)
144   {
145     columns.add(column);
146   }
147
148   /**
149    * Returns a list of <code>DatabaseColumn</code> objects describing the
150    * columns of this table.
151    * <p>
152    * Warning! The underlying <code>ArrayList</code> is not synchronized.
153    *
154    * @return an <code>ArrayList</code> of <code>DatabaseColumn</code>
155    */

156   public ArrayList JavaDoc getColumns()
157   {
158     return columns;
159   }
160
161   /**
162    * Returns the <code>DatabaseColumn</code> object matching the given column
163    * name or <code>null</code> if not found (the case is ignored).
164    *
165    * @param columnName column name to look for
166    * @return a <code>DatabaseColumn</code> value or <code>null</code>
167    */

168   public DatabaseColumn getColumn(String JavaDoc columnName)
169   {
170     DatabaseColumn c;
171     for (Iterator JavaDoc i = columns.iterator(); i.hasNext();)
172     {
173       c = (DatabaseColumn) i.next();
174       if (columnName.equalsIgnoreCase(c.getName()))
175         return c;
176
177     }
178     return null;
179   }
180
181   /**
182    * Returns the <code>DatabaseColumn</code> object matching the given column
183    * name or <code>null</code> if not found (the case can be enforced).
184    *
185    * @param columnName column name to look for
186    * @param isCaseSensitive true if name matching must be case sensitive
187    * @return a <code>DatabaseColumn</code> value or <code>null</code>
188    */

189   public DatabaseColumn getColumn(String JavaDoc columnName, boolean isCaseSensitive)
190   {
191     if (!isCaseSensitive)
192       return getColumn(columnName);
193
194     DatabaseColumn c;
195     for (Iterator JavaDoc i = columns.iterator(); i.hasNext();)
196     {
197       c = (DatabaseColumn) i.next();
198       if (columnName.equals(c.getName()))
199         return c;
200
201     }
202     return null;
203   }
204
205   /**
206    * Returns the dependingTables value.
207    *
208    * @return Returns the dependingTables.
209    */

210   public ArrayList JavaDoc getDependingTables()
211   {
212     return dependingTables;
213   }
214
215   /**
216    * Returns the lock for this table.
217    *
218    * @return a <code>TransactionLogicalLock</code> instance
219    */

220   public TransactionLogicalLock getLock()
221   {
222     return lock;
223   }
224
225   /**
226    * Retain locks held by a transaction when the schema is reloaded.
227    *
228    * @param oldTable the previous version of this table
229    */

230   void setLock(DatabaseTable oldTable)
231   {
232     lock = oldTable.lock;
233   }
234
235   /**
236    * Gets the name of the table.
237    *
238    * @return the table name
239    */

240   public String JavaDoc getName()
241   {
242     return name;
243   }
244
245   /**
246    * Returns the schema value.
247    *
248    * @return Returns the schema.
249    */

250   public String JavaDoc getSchema()
251   {
252     return schema;
253   }
254
255   /**
256    * Sets the schema value.
257    *
258    * @param schema The schema to set.
259    */

260   public void setSchema(String JavaDoc schema)
261   {
262     this.schema = schema;
263   }
264
265   /**
266    * Returns a list of <code>DatabaseColumn</code> objects representing the
267    * unique columns of this table.
268    * <p>
269    * Warning! The underlying <code>ArrayList</code> is not synchronized.
270    *
271    * @return an <code>ArrayList</code> of <code>DatabaseColumn</code>
272    * objects
273    */

274   public ArrayList JavaDoc getUniqueColumns()
275   {
276     ArrayList JavaDoc cols = new ArrayList JavaDoc();
277     Iterator JavaDoc i;
278     DatabaseColumn c;
279
280     for (i = columns.iterator(); i.hasNext();)
281     {
282       c = (DatabaseColumn) i.next();
283       if (c.isUnique())
284         cols.add(c);
285     }
286     return cols;
287   }
288
289   /**
290    * Merges this table with the given table. Both columns and depending tables
291    * are merged.
292    * <p>
293    * All missing columns are added if no conflict is detected. An exception is
294    * thrown if the given table columns conflicts with this one.
295    *
296    * @param table the table to merge
297    * @throws SQLException if the schemas conflict
298    */

299   public void merge(DatabaseTable table) throws SQLException JavaDoc
300   {
301     if (table == null)
302       return;
303
304     if (dependingTables == null)
305       dependingTables = table.getDependingTables();
306     else
307     {
308       ArrayList JavaDoc otherDependingTables = table.getDependingTables();
309       if (otherDependingTables != null)
310         for (Iterator JavaDoc iter = otherDependingTables.iterator(); iter.hasNext();)
311           addDependingTable((String JavaDoc) iter.next());
312     }
313
314     ArrayList JavaDoc otherColumns = table.getColumns();
315     if (otherColumns == null)
316       return;
317
318     DatabaseColumn c, original;
319     int size = otherColumns.size();
320     for (int i = 0; i < size; i++)
321     {
322       c = (DatabaseColumn) otherColumns.get(i);
323       original = getColumn(c.getName());
324       if (original == null)
325         addColumn(c);
326       else
327       {
328         if (!original.equalsIgnoreType(c))
329           throw new SQLException JavaDoc("Unable to merge table [" + table.getName()
330               + "]: column '" + c.getName() + "' definition mismatch");
331       }
332     }
333   }
334
335   /**
336    * Drops a <code>DatabaseColumn</code> object from this table.
337    * <p>
338    * Warning! The underlying <code>ArrayList</code> is not synchronized.
339    *
340    * @param columnName a <code>String</code> that maps to a
341    * <code>DatabaseColumn</code> value
342    */

343   public void removeColumn(String JavaDoc columnName)
344   {
345     columns.remove(getColumn(columnName));
346   }
347
348   /**
349    * Drops a <code>DatabaseColumn</code> object from this table.
350    * <p>
351    * Warning! The underlying <code>ArrayList</code> is not synchronized.
352    *
353    * @param column a <code>DatabaseColumn</code> value
354    */

355   public void removeColumn(DatabaseColumn column)
356   {
357     columns.remove(column);
358   }
359
360   /**
361    * Updates this table with the given table's columns. All missing columns are
362    * added and if the given table columns conflicts with this one, the current
363    * column definition is overriden with the provided one. Note that existing
364    * locks (if any) are preserved.
365    * <p>
366    * Warning! Data structures of the given table are not cloned.
367    *
368    * @param table the table to use to update the current one
369    */

370   public void updateColumns(DatabaseTable table)
371   {
372     if (table == null)
373       return;
374
375     ArrayList JavaDoc otherColumns = table.getColumns();
376
377     // Remove columns that do not exist anymore in new schema
378
for (Iterator JavaDoc iter = columns.iterator(); iter.hasNext();)
379     {
380       DatabaseColumn c = (DatabaseColumn) iter.next();
381       if (!otherColumns.contains(c))
382         iter.remove();
383     }
384
385     // Add missing columns and update existing ones
386
int size = otherColumns.size();
387     for (int i = 0; i < size; i++)
388     {
389       DatabaseColumn c = (DatabaseColumn) otherColumns.get(i);
390       DatabaseColumn originalColumn = getColumn(c.getName());
391       if (originalColumn == null)
392         addColumn(c);
393       else
394       {
395         originalColumn.setType(c.getType());
396         originalColumn.setIsUnique(c.isUnique());
397       }
398     }
399   }
400
401   /**
402    * Two <code>DatabaseTable</code> are considered equal if they have the same
403    * name and the same columns.
404    *
405    * @param other the object to compare with
406    * @return <code>true</code> if the tables are equal
407    */

408   public boolean equals(Object JavaDoc other)
409   {
410     if ((other == null) || !(other instanceof DatabaseTable))
411       return false;
412
413     DatabaseTable t = (DatabaseTable) other;
414
415     // Compare name
416
if (!name.equals(t.getName()))
417       return false;
418
419     // Compare schema
420
if (t.getSchema() == null)
421     {
422       if (schema != null)
423         return false;
424     }
425     else
426     {
427       if (!t.getSchema().equals(schema))
428         return false;
429     }
430     // Compare columns
431
if (t.getColumns() == null)
432       return columns == null;
433     else
434       return t.getColumns().equals(columns);
435   }
436
437   /**
438    * This function is the same as equals but ignores the column type.
439    *
440    * @param other the object to compare with
441    * @return <code>true</code> if the table are equal ignoring the columns
442    * type
443    * @see #equals(Object)
444    */

445   public boolean equalsIgnoreType(Object JavaDoc other)
446   {
447     if ((other == null) || !(other instanceof DatabaseTable))
448       return false;
449
450     DatabaseTable t = (DatabaseTable) other;
451     // Compare name
452
if (!name.equals(t.getName()))
453       return false;
454
455     // Compare schema
456
if (t.getSchema() == null)
457     {
458       if (schema != null)
459         return false;
460     }
461     else
462     {
463       if (!t.getSchema().equals(schema))
464         return false;
465     }
466
467     DatabaseColumn c1, c2;
468     Iterator JavaDoc iter = columns.iterator();
469     while (iter.hasNext())
470     {
471       c1 = (DatabaseColumn) iter.next();
472       c2 = t.getColumn(c1.getName());
473
474       if (!c1.equalsIgnoreType(c2))
475         return false; // Not compatible
476
}
477     return true;
478   }
479
480   /**
481    * @see java.lang.Object#toString()
482    */

483   public String JavaDoc toString()
484   {
485     return name + "(" + columns + ")";
486   }
487 }
488
Popular Tags