blob: da8f3335102ceadca3576f8aea0c44c5bf523952 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.db.internal;
import java.text.Collator;
import java.util.Iterator;
import java.util.List;
import org.eclipse.datatools.modelbase.sql.constraints.PrimaryKey;
import org.eclipse.datatools.modelbase.sql.tables.BaseTable;
import org.eclipse.jpt.db.Column;
import org.eclipse.jpt.db.ForeignKey;
import org.eclipse.jpt.db.Table;
import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.iterators.ArrayIterator;
import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
/**
* Wrap a DTP Table
*/
final class DTPTableWrapper
extends DTPDatabaseObjectWrapper
implements Table
{
// the wrapped DTP table
private final org.eclipse.datatools.modelbase.sql.tables.Table dtpTable;
// lazy-initialized
private DTPColumnWrapper[] columns;
// lazy-initialized
private DTPColumnWrapper[] primaryKeyColumns;
// lazy-initialized
private DTPForeignKeyWrapper[] foreignKeys;
private static final DTPColumnWrapper[] EMPTY_COLUMNS = new DTPColumnWrapper[0];
private static final DTPForeignKeyWrapper[] EMPTY_FOREIGN_KEYS = new DTPForeignKeyWrapper[0];
// ********** constructor **********
DTPTableWrapper(DTPSchemaWrapper schema, org.eclipse.datatools.modelbase.sql.tables.Table dtpTable) {
super(schema, dtpTable);
this.dtpTable = dtpTable;
}
// ********** DTPWrapper implementation **********
@Override
synchronized void catalogObjectChanged() {
super.catalogObjectChanged();
this.getConnectionProfile().tableChanged(this);
}
// ********** Table implementation **********
public String getName() {
return this.dtpTable.getName();
}
public DTPSchemaWrapper getSchema() {
return (DTPSchemaWrapper) this.getParent();
}
// ***** columns
public Iterator<Column> columns() {
return new ArrayIterator<Column>(this.getColumns());
}
private Iterator<DTPColumnWrapper> columnWrappers() {
return new ArrayIterator<DTPColumnWrapper>(this.getColumns());
}
private synchronized DTPColumnWrapper[] getColumns() {
if (this.columns == null) {
this.columns = this.buildColumns();
}
return this.columns;
}
private DTPColumnWrapper[] buildColumns() {
List<org.eclipse.datatools.modelbase.sql.tables.Column> dtpColumns = this.getDTPColumns();
DTPColumnWrapper[] result = new DTPColumnWrapper[dtpColumns.size()];
for (int i = result.length; i-- > 0;) {
result[i] = new DTPColumnWrapper(this, dtpColumns.get(i));
}
return CollectionTools.sort(result);
}
// minimize scope of suppressed warnings
@SuppressWarnings("unchecked")
private List<org.eclipse.datatools.modelbase.sql.tables.Column> getDTPColumns() {
return this.dtpTable.getColumns();
}
public int columnsSize() {
return this.getColumns().length;
}
public DTPColumnWrapper getColumnNamed(String name) {
return this.selectDatabaseObjectNamed(this.getColumns(), name);
}
/**
* return the column for the specified DTP column
*/
DTPColumnWrapper getColumn(org.eclipse.datatools.modelbase.sql.tables.Column dtpColumn) {
// try to short-circuit the search
return this.wraps(dtpColumn.getTable()) ?
this.getColumn_(dtpColumn)
:
this.getSchema().getColumn(dtpColumn);
}
/**
* assume the table contains the specified column
*/
DTPColumnWrapper getColumn_(org.eclipse.datatools.modelbase.sql.tables.Column dtpColumn) {
for (DTPColumnWrapper column : this.getColumns()) {
if (column.wraps(dtpColumn)) {
return column;
}
}
throw new IllegalArgumentException("invalid DTP column: " + dtpColumn); //$NON-NLS-1$
}
public Iterator<String> sortedColumnIdentifiers() {
// the columns are already sorted
return new TransformationIterator<DTPColumnWrapper, String>(this.columnWrappers()) {
@Override
protected String transform(DTPColumnWrapper next) {
return next.getIdentifier();
}
};
}
public DTPColumnWrapper getColumnForIdentifier(String identifier) {
return this.selectDatabaseObjectForIdentifier(this.getColumns(), identifier);
}
// ***** primaryKeyColumns
public Iterator<Column> primaryKeyColumns() {
return new ArrayIterator<Column>(this.getPrimaryKeyColumns());
}
public DTPColumnWrapper getPrimaryKeyColumn() {
DTPColumnWrapper[] pkColumns = this.getPrimaryKeyColumns();
if (pkColumns.length != 1) {
throw new IllegalStateException("multiple primary key columns: " + pkColumns.length); //$NON-NLS-1$
}
return pkColumns[0];
}
private synchronized DTPColumnWrapper[] getPrimaryKeyColumns() {
if (this.primaryKeyColumns == null) {
this.primaryKeyColumns = this.buildPrimaryKeyColumns();
}
return this.primaryKeyColumns;
}
private DTPColumnWrapper[] buildPrimaryKeyColumns() {
if ( ! (this.dtpTable instanceof BaseTable)) {
return EMPTY_COLUMNS;
}
PrimaryKey pk = ((BaseTable) this.dtpTable).getPrimaryKey();
if (pk == null) {
// no PK was defined
return EMPTY_COLUMNS;
}
List<org.eclipse.datatools.modelbase.sql.tables.Column> pkColumns = this.getColumns(pk);
DTPColumnWrapper[] result = new DTPColumnWrapper[pkColumns.size()];
for (int i = result.length; i-- > 0;) {
result[i] = this.getColumn(pkColumns.get(i));
}
return result;
}
// minimize scope of suppressed warnings
@SuppressWarnings("unchecked")
private List<org.eclipse.datatools.modelbase.sql.tables.Column> getColumns(PrimaryKey pk) {
return pk.getMembers();
}
public int primaryKeyColumnsSize() {
return this.getPrimaryKeyColumns().length;
}
boolean primaryKeyColumnsContains(Column column) {
return CollectionTools.contains(this.getPrimaryKeyColumns(), column);
}
// ***** foreignKeys
public Iterator<ForeignKey> foreignKeys() {
return new ArrayIterator<ForeignKey>(this.getForeignKeys());
}
private synchronized DTPForeignKeyWrapper[] getForeignKeys() {
if (this.foreignKeys == null) {
this.foreignKeys = this.buildForeignKeys();
}
return this.foreignKeys;
}
private DTPForeignKeyWrapper[] buildForeignKeys() {
if ( ! (this.dtpTable instanceof BaseTable)) {
return EMPTY_FOREIGN_KEYS;
}
List<org.eclipse.datatools.modelbase.sql.constraints.ForeignKey> dtpForeignKeys = this.getDTPForeignKeys();
DTPForeignKeyWrapper[] result = new DTPForeignKeyWrapper[dtpForeignKeys.size()];
for (int i = result.length; i-- > 0;) {
result[i] = new DTPForeignKeyWrapper(this, dtpForeignKeys.get(i));
}
return result;
}
@SuppressWarnings("unchecked")
private List<org.eclipse.datatools.modelbase.sql.constraints.ForeignKey> getDTPForeignKeys() {
return ((BaseTable) this.dtpTable).getForeignKeys();
}
public int foreignKeysSize() {
return this.getForeignKeys().length;
}
/**
* return whether the specified column is a base column for at least one
* of the the table's foreign keys
*/
boolean foreignKeyBaseColumnsContains(Column column) {
for (DTPForeignKeyWrapper fkWrapper : this.getForeignKeys()) {
if (fkWrapper.baseColumnsContains(column)) {
return true;
}
}
return false;
}
// ***** join table
public boolean isPossibleJoinTable() {
if (this.getForeignKeys().length != 2) {
return false; // the table must have exactly 2 foreign keys
}
for (Column column : this.getColumns()) {
if ( ! this.foreignKeyBaseColumnsContains(column)) {
return false; // all the table's columns must belong to one (or both) of the 2 foreign keys
}
}
return true;
}
/**
* If the table name is FOO_BAR and it joins tables FOO and BAR,
* return the foreign key to FOO;
* if the table name is BAR_FOO and it joins tables FOO and BAR,
* return the foreign key to BAR;
* otherwise simply return the first foreign key in the array.
*/
public ForeignKey getJoinTableOwningForeignKey() {
ForeignKey fk0 = this.getForeignKeys()[0];
String name0 = fk0.getReferencedTable().getName();
ForeignKey fk1 = this.getForeignKeys()[1];
String name1 = fk1.getReferencedTable().getName();
return this.getName().equals(name1 + '_' + name0) ? fk1 : fk0;
}
public ForeignKey getJoinTableNonOwningForeignKey() {
ForeignKey fk0 = this.getForeignKeys()[0];
ForeignKey fk1 = this.getForeignKeys()[1];
ForeignKey ofk = this.getJoinTableOwningForeignKey();
return (ofk == fk0) ? fk1 : fk0;
}
/**
* Hmmm....
* We might want to go to the platform to allow a vendor-specific
* comparison here;
* but, since all the names are coming directly from the database
* (i.e. there are no conversions to Java identifiers etc.), it seems
* like we can just compare them directly and ignore case-sensitivity
* issues.... ~bjv
*/
public boolean joinTableNameIsDefault() {
return this.getName().equals(this.buildDefaultJoinTableName());
}
private String buildDefaultJoinTableName() {
return this.getJoinTableOwningTable().getName()
+ '_'
+ this.getJoinTableNonOwningTable().getName();
}
private Table getJoinTableOwningTable() {
return this.getJoinTableOwningForeignKey().getReferencedTable();
}
private Table getJoinTableNonOwningTable() {
return this.getJoinTableNonOwningForeignKey().getReferencedTable();
}
// ********** Comparable implementation **********
public int compareTo(Table table) {
return Collator.getInstance().compare(this.getName(), table.getName());
}
// ********** internal methods **********
boolean wraps(org.eclipse.datatools.modelbase.sql.tables.Table table) {
return this.dtpTable == table;
}
/**
* return the table for the specified DTP table
*/
DTPTableWrapper getTable(org.eclipse.datatools.modelbase.sql.tables.Table table) {
// try to short-circuit the search
return this.wraps(table) ? this : this.getSchema().getTable(table);
}
// ********** listening **********
@Override
synchronized void startListening() {
if (this.foreignKeys != null) {
this.startForeignKeys();
}
if (this.columns != null) {
this.startColumns();
}
super.startListening();
}
private void startForeignKeys() {
for (DTPForeignKeyWrapper foreignKey : this.foreignKeys) {
foreignKey.startListening();
}
}
private void startColumns() {
for (DTPColumnWrapper column : this.columns) {
column.startListening();
}
}
@Override
synchronized void stopListening() {
if (this.foreignKeys != null) {
this.stopForeignKeys();
}
if (this.columns != null) {
this.stopColumns();
}
super.stopListening();
}
private void stopForeignKeys() {
for (DTPForeignKeyWrapper foreignKey : this.foreignKeys) {
foreignKey.stopListening();
}
}
private void stopColumns() {
for (DTPColumnWrapper column : this.columns) {
column.stopListening();
}
}
// ********** clear **********
@Override
void clear() {
if (this.foreignKeys != null) {
this.clearForeignKeys();
}
// the table does not "contain" the pk columns, so no need to forward #clear()
this.primaryKeyColumns = null;
if (this.columns != null) {
this.clearColumns();
}
}
private void clearForeignKeys() {
this.stopForeignKeys();
for (DTPForeignKeyWrapper foreignKey : this.foreignKeys) {
foreignKey.clear();
}
this.foreignKeys = null;
}
private void clearColumns() {
this.stopColumns();
for (DTPColumnWrapper column : this.columns) {
column.clear();
}
this.columns = null;
}
}