blob: f589a7d6bda28cdab80147bd0e46dcfd9b16c0c4 [file] [log] [blame]
package org.apache.ddlutils.model;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.Serializable;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collection;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
/**
* Represents a table in the database model.
*
* @version $Revision$
*/
public class Table implements Serializable
{
/** Unique ID for serialization purposes. */
private static final long serialVersionUID = -5541154961302342608L;
/** The catalog of this table as read from the database. */
private String _catalog = null;
/** The table's schema. */
private String _schema = null;
/** The name. */
private String _name = null;
/** A description of the table. */
private String _description = null;
/** The table's type as read from the database. */
private String _type = null;
/** The columns in this table. */
private ArrayList _columns = new ArrayList();
/** The foreign keys associated to this table. */
private ArrayList _foreignKeys = new ArrayList();
/** The indices applied to this table. */
private ArrayList _indices = new ArrayList();
/**
* Returns the catalog of this table as read from the database.
*
* @return The catalog
*/
public String getCatalog()
{
return _catalog;
}
/**
* Sets the catalog of this table.
*
* @param catalog The catalog
*/
public void setCatalog(String catalog)
{
_catalog = catalog;
}
/**
* Returns the schema of this table as read from the database.
*
* @return The schema
*/
public String getSchema()
{
return _schema;
}
/**
* Sets the schema of this table.
*
* @param schema The schema
*/
public void setSchema(String schema)
{
_schema = schema;
}
/**
* Returns the type of this table as read from the database.
*
* @return The type
*/
public String getType()
{
return _type;
}
/**
* Sets the type of this table.
*
* @param type The type
*/
public void setType(String type)
{
_type = type;
}
/**
* Returns the name of the table.
*
* @return The name
*/
public String getName()
{
return _name;
}
/**
* Sets the name of the table.
*
* @param name The name
*/
public void setName(String name)
{
_name = name;
}
/**
* Returns the description of the table.
*
* @return The description
*/
public String getDescription()
{
return _description;
}
/**
* Sets the description of the table.
*
* @param description The description
*/
public void setDescription(String description)
{
_description = description;
}
/**
* Returns the number of columns in this table.
*
* @return The number of columns
*/
public int getColumnCount()
{
return _columns.size();
}
/**
* Returns the column at the specified position.
*
* @param idx The column index
* @return The column at this position
*/
public Column getColumn(int idx)
{
return (Column)_columns.get(idx);
}
/**
* Returns the columns in this table.
*
* @return The columns
*/
public Column[] getColumns()
{
return (Column[])_columns.toArray(new Column[_columns.size()]);
}
/**
* Adds the given column.
*
* @param column The column
*/
public void addColumn(Column column)
{
if (column != null)
{
_columns.add(column);
}
}
/**
* Adds the given column at the specified position.
*
* @param idx The index where to add the column
* @param column The column
*/
public void addColumn(int idx, Column column)
{
if (column != null)
{
_columns.add(idx, column);
}
}
/**
* Adds the column after the given previous column.
*
* @param previousColumn The column to add the new column after; use
* <code>null</code> for adding at the begin
* @param column The column
*/
public void addColumn(Column previousColumn, Column column)
{
if (column != null)
{
if (previousColumn == null)
{
_columns.add(0, column);
}
else
{
_columns.add(_columns.indexOf(previousColumn), column);
}
}
}
/**
* Adds the given columns.
*
* @param columns The columns
*/
public void addColumns(Collection columns)
{
for (Iterator it = columns.iterator(); it.hasNext();)
{
addColumn((Column)it.next());
}
}
/**
* Removes the given column.
*
* @param column The column to remove
*/
public void removeColumn(Column column)
{
if (column != null)
{
_columns.remove(column);
}
}
/**
* Removes all columns of this table. Note that this does not change
* indexes or foreign keys, so it might leave the table object in
* an illegal state.
*/
public void removeAllColumns()
{
_columns.clear();
}
/**
* Removes the indicated column.
*
* @param idx The index of the column to remove
*/
public void removeColumn(int idx)
{
_columns.remove(idx);
}
/**
* Returns the number of foreign keys.
*
* @return The number of foreign keys
*/
public int getForeignKeyCount()
{
return _foreignKeys.size();
}
/**
* Returns the foreign key at the given position.
*
* @param idx The foreign key index
* @return The foreign key
*/
public ForeignKey getForeignKey(int idx)
{
return (ForeignKey)_foreignKeys.get(idx);
}
/**
* Returns the foreign keys of this table.
*
* @return The foreign keys
*/
public ForeignKey[] getForeignKeys()
{
return (ForeignKey[])_foreignKeys.toArray(new ForeignKey[_foreignKeys.size()]);
}
/**
* Adds the given foreign key.
*
* @param foreignKey The foreign key
*/
public void addForeignKey(ForeignKey foreignKey)
{
if (foreignKey != null)
{
_foreignKeys.add(foreignKey);
}
}
/**
* Adds the given foreign key at the specified position.
*
* @param idx The index to add the foreign key at
* @param foreignKey The foreign key
*/
public void addForeignKey(int idx, ForeignKey foreignKey)
{
if (foreignKey != null)
{
_foreignKeys.add(idx, foreignKey);
}
}
/**
* Adds the given foreign keys.
*
* @param foreignKeys The foreign keys
*/
public void addForeignKeys(Collection foreignKeys)
{
for (Iterator it = foreignKeys.iterator(); it.hasNext();)
{
addForeignKey((ForeignKey)it.next());
}
}
/**
* Removes all foreign keys.
*/
public void removeAllForeignKeys()
{
_foreignKeys.clear();
}
/**
* Removes the given foreign key.
*
* @param foreignKey The foreign key to remove
*/
public void removeForeignKey(ForeignKey foreignKey)
{
if (foreignKey != null)
{
_foreignKeys.remove(foreignKey);
}
}
/**
* Removes the indicated foreign key.
*
* @param idx The index of the foreign key to remove
*/
public void removeForeignKey(int idx)
{
_foreignKeys.remove(idx);
}
/**
* Returns the number of indices.
*
* @return The number of indices
*/
public int getIndexCount()
{
return _indices.size();
}
/**
* Returns the index at the specified position.
*
* @param idx The position
* @return The index
*/
public Index getIndex(int idx)
{
return (Index)_indices.get(idx);
}
/**
* Adds the given index.
*
* @param index The index
*/
public void addIndex(Index index)
{
if (index != null)
{
_indices.add(index);
}
}
/**
* Adds the given index at the specified position.
*
* @param idx The position to add the index at
* @param index The index
*/
public void addIndex(int idx, Index index)
{
if (index != null)
{
_indices.add(idx, index);
}
}
/**
* Adds the given indices.
*
* @param indices The indices
*/
public void addIndices(Collection indices)
{
for (Iterator it = indices.iterator(); it.hasNext();)
{
addIndex((Index)it.next());
}
}
/**
* Returns the indices of this table.
*
* @return The indices
*/
public Index[] getIndices()
{
return (Index[])_indices.toArray(new Index[_indices.size()]);
}
/**
* Gets a list of non-unique indices on this table.
*
* @return The unique indices
*/
public Index[] getNonUniqueIndices()
{
Collection nonUniqueIndices = CollectionUtils.select(_indices, new Predicate() {
public boolean evaluate(Object input) {
return !((Index)input).isUnique();
}
});
return (Index[])nonUniqueIndices.toArray(new Index[nonUniqueIndices.size()]);
}
/**
* Gets a list of unique indices on this table.
*
* @return The unique indices
*/
public Index[] getUniqueIndices()
{
Collection uniqueIndices = CollectionUtils.select(_indices, new Predicate() {
public boolean evaluate(Object input) {
return ((Index)input).isUnique();
}
});
return (Index[])uniqueIndices.toArray(new Index[uniqueIndices.size()]);
}
/**
* Removes the given index.
*
* @param index The index to remove
*/
public void removeIndex(Index index)
{
if (index != null)
{
_indices.remove(index);
}
}
/**
* Removes the indicated index.
*
* @param idx The position of the index to remove
*/
public void removeIndex(int idx)
{
_indices.remove(idx);
}
// Helper methods
//-------------------------------------------------------------------------
/**
* Determines whether there is at least one primary key column on this table.
*
* @return <code>true</code> if there are one or more primary key columns
*/
public boolean hasPrimaryKey()
{
for (Iterator it = _columns.iterator(); it.hasNext(); )
{
Column column = (Column)it.next();
if (column.isPrimaryKey())
{
return true;
}
}
return false;
}
/**
* Finds the column with the specified name, using case insensitive matching.
* Note that this method is not called getColumn(String) to avoid introspection
* problems.
*
* @param name The name of the column
* @return The column or <code>null</code> if there is no such column
*/
public Column findColumn(String name)
{
return findColumn(name, false);
}
/**
* Finds the column with the specified name, using case insensitive matching.
* Note that this method is not called getColumn(String) to avoid introspection
* problems.
*
* @param name The name of the column
* @param caseSensitive Whether case matters for the names
* @return The column or <code>null</code> if there is no such column
*/
public Column findColumn(String name, boolean caseSensitive)
{
for (Iterator it = _columns.iterator(); it.hasNext(); )
{
Column column = (Column)it.next();
if (caseSensitive)
{
if (column.getName().equals(name))
{
return column;
}
}
else
{
if (column.getName().equalsIgnoreCase(name))
{
return column;
}
}
}
return null;
}
/**
* Determines the index of the given column.
*
* @param column The column
* @return The index or <code>-1</code> if it is no column of this table
*/
public int getColumnIndex(Column column)
{
int idx = 0;
for (Iterator it = _columns.iterator(); it.hasNext(); idx++)
{
if (column == it.next())
{
return idx;
}
}
return -1;
}
/**
* Finds the index with the specified name, using case insensitive matching.
* Note that this method is not called getIndex to avoid introspection
* problems.
*
* @param name The name of the index
* @return The index or <code>null</code> if there is no such index
*/
public Index findIndex(String name)
{
return findIndex(name, false);
}
/**
* Finds the index with the specified name, using case insensitive matching.
* Note that this method is not called getIndex to avoid introspection
* problems.
*
* @param name The name of the index
* @param caseSensitive Whether case matters for the names
* @return The index or <code>null</code> if there is no such index
*/
public Index findIndex(String name, boolean caseSensitive)
{
for (int idx = 0; idx < getIndexCount(); idx++)
{
Index index = getIndex(idx);
if (caseSensitive)
{
if (index.getName().equals(name))
{
return index;
}
}
else
{
if (index.getName().equalsIgnoreCase(name))
{
return index;
}
}
}
return null;
}
/**
* Finds the foreign key in this table that is equal to the supplied foreign key.
*
* @param key The foreign key to search for
* @return The found foreign key
*/
public ForeignKey findForeignKey(ForeignKey key)
{
for (int idx = 0; idx < getForeignKeyCount(); idx++)
{
ForeignKey fk = getForeignKey(idx);
if (fk.equals(key))
{
return fk;
}
}
return null;
}
/**
* Finds the foreign key in this table that is equal to the supplied foreign key.
*
* @param key The foreign key to search for
* @param caseSensitive Whether case matters for the names
* @return The found foreign key
*/
public ForeignKey findForeignKey(ForeignKey key, boolean caseSensitive)
{
for (int idx = 0; idx < getForeignKeyCount(); idx++)
{
ForeignKey fk = getForeignKey(idx);
if ((caseSensitive && fk.equals(key)) ||
(!caseSensitive && fk.equalsIgnoreCase(key)))
{
return fk;
}
}
return null;
}
/**
* Returns the foreign key referencing this table if it exists.
*
* @return The self-referencing foreign key if any
*/
public ForeignKey getSelfReferencingForeignKey()
{
for (int idx = 0; idx < getForeignKeyCount(); idx++)
{
ForeignKey fk = getForeignKey(idx);
if (this.equals(fk.getForeignTable()))
{
return fk;
}
}
return null;
}
/**
* Returns the primary key columns of this table.
*
* @return The primary key columns
*/
public Column[] getPrimaryKeyColumns()
{
Collection pkColumns = CollectionUtils.select(_columns, new Predicate() {
public boolean evaluate(Object input) {
return ((Column)input).isPrimaryKey();
}
});
return (Column[])pkColumns.toArray(new Column[pkColumns.size()]);
}
/**
* Returns the names of the primary key columns of this table.
*
* @return The primary key column names
*/
public String[] getPrimaryKeyColumnNames()
{
Column[] pkColumns = getPrimaryKeyColumns();
String[] names = new String[pkColumns.length];
for (int colIdx = 0; colIdx < pkColumns.length; colIdx++)
{
names[colIdx] = pkColumns[colIdx].getName();
}
return names;
}
/**
* Returns the auto increment columns in this table. If no incrementcolumns
* are found, it will return an empty array.
*
* @return The columns
*/
public Column[] getAutoIncrementColumns()
{
Collection autoIncrColumns = CollectionUtils.select(_columns, new Predicate() {
public boolean evaluate(Object input) {
return ((Column)input).isAutoIncrement();
}
});
return (Column[])autoIncrColumns.toArray(new Column[autoIncrColumns.size()]);
}
/**
* Sorts the foreign keys alphabetically.
*
* @param caseSensitive Whether case matters
*/
public void sortForeignKeys(final boolean caseSensitive)
{
if (!_foreignKeys.isEmpty())
{
final Collator collator = Collator.getInstance();
Collections.sort(_foreignKeys, new Comparator() {
public int compare(Object obj1, Object obj2)
{
String fk1Name = ((ForeignKey)obj1).getName();
String fk2Name = ((ForeignKey)obj2).getName();
if (!caseSensitive)
{
fk1Name = (fk1Name != null ? fk1Name.toLowerCase() : null);
fk2Name = (fk2Name != null ? fk2Name.toLowerCase() : null);
}
return collator.compare(fk1Name, fk2Name);
}
});
}
}
/**
* {@inheritDoc}
*/
public boolean equals(Object obj)
{
if (obj instanceof Table)
{
Table other = (Table)obj;
// Note that this compares case sensitive
// TODO: For now we ignore catalog and schema (type should be irrelevant anyways)
return new EqualsBuilder().append(_name, other._name)
.append(_columns, other._columns)
.append(new HashSet(_foreignKeys), new HashSet(other._foreignKeys))
.append(new HashSet(_indices), new HashSet(other._indices))
.isEquals();
}
else
{
return false;
}
}
/**
* {@inheritDoc}
*/
public int hashCode()
{
// TODO: For now we ignore catalog and schema (type should be irrelevant anyways)
return new HashCodeBuilder(17, 37).append(_name)
.append(_columns)
.append(new HashSet(_foreignKeys))
.append(new HashSet(_indices))
.toHashCode();
}
/**
* {@inheritDoc}
*/
public String toString()
{
StringBuffer result = new StringBuffer();
result.append("Table [name=");
result.append(getName());
result.append("; ");
result.append(getColumnCount());
result.append(" columns]");
return result.toString();
}
/**
* Returns a verbose string representation of this table.
*
* @return The string representation
*/
public String toVerboseString()
{
StringBuffer result = new StringBuffer();
result.append("Table [name=");
result.append(getName());
result.append("; catalog=");
result.append(getCatalog());
result.append("; schema=");
result.append(getCatalog());
result.append("; type=");
result.append(getType());
result.append("] columns:");
for (int idx = 0; idx < getColumnCount(); idx++)
{
result.append(" ");
result.append(getColumn(idx).toVerboseString());
}
result.append("; indices:");
for (int idx = 0; idx < getIndexCount(); idx++)
{
result.append(" ");
result.append(getIndex(idx).toVerboseString());
}
result.append("; foreign keys:");
for (int idx = 0; idx < getForeignKeyCount(); idx++)
{
result.append(" ");
result.append(getForeignKey(idx).toVerboseString());
}
return result.toString();
}
}