blob: 683c33b13792a3e6f37eb0f058117903d25697d8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2009 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.jpa.db.internal;
import java.util.List;
import org.eclipse.datatools.modelbase.sql.constraints.PrimaryKey;
import org.eclipse.datatools.modelbase.sql.tables.BaseTable;
import org.eclipse.jpt.common.utility.internal.ArrayTools;
import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable;
import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable;
import org.eclipse.jpt.jpa.db.Column;
import org.eclipse.jpt.jpa.db.DatabaseObject;
import org.eclipse.jpt.jpa.db.ForeignKey;
import org.eclipse.jpt.jpa.db.Table;
/**
* 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 Iterable<Column> getColumns() {
return new ArrayIterable<Column>(this.getColumnArray());
}
private Iterable<DTPColumnWrapper> getColumnWrappers() {
return new ArrayIterable<DTPColumnWrapper>(this.getColumnArray());
}
private synchronized DTPColumnWrapper[] getColumnArray() {
if (this.columns == null) {
this.columns = this.buildColumnArray();
}
return this.columns;
}
private DTPColumnWrapper[] buildColumnArray() {
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 ArrayTools.sort(result, DEFAULT_COMPARATOR);
}
// minimize scope of suppressed warnings
@SuppressWarnings("unchecked")
private List<org.eclipse.datatools.modelbase.sql.tables.Column> getDTPColumns() {
return this.dtpTable.getColumns();
}
public int getColumnsSize() {
return this.getColumnArray().length;
}
public DTPColumnWrapper getColumnNamed(String name) {
return this.selectDatabaseObjectNamed(this.getColumnWrappers(), 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.getColumnArray()) {
if (column.wraps(dtpColumn)) {
return column;
}
}
throw new IllegalArgumentException("invalid DTP column: " + dtpColumn); //$NON-NLS-1$
}
public Iterable<String> getSortedColumnIdentifiers() {
// the columns are already sorted
return new TransformationIterable<DatabaseObject, String>(this.getColumnWrappers(), IDENTIFIER_TRANSFORMER);
}
public DTPColumnWrapper getColumnForIdentifier(String identifier) {
return this.selectDatabaseObjectForIdentifier(this.getColumnWrappers(), identifier);
}
// ***** primaryKeyColumns
public Iterable<Column> getPrimaryKeyColumns() {
return new ArrayIterable<Column>(this.getPrimaryKeyColumnArray());
}
public DTPColumnWrapper getPrimaryKeyColumn() {
DTPColumnWrapper[] pkColumns = this.getPrimaryKeyColumnArray();
if (pkColumns.length != 1) {
throw new IllegalStateException("multiple primary key columns: " + pkColumns.length); //$NON-NLS-1$
}
return pkColumns[0];
}
private synchronized DTPColumnWrapper[] getPrimaryKeyColumnArray() {
if (this.primaryKeyColumns == null) {
this.primaryKeyColumns = this.buildPrimaryKeyColumnArray();
}
return this.primaryKeyColumns;
}
private DTPColumnWrapper[] buildPrimaryKeyColumnArray() {
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 getPrimaryKeyColumnsSize() {
return this.getPrimaryKeyColumnArray().length;
}
boolean primaryKeyColumnsContains(Column column) {
return ArrayTools.contains(this.getPrimaryKeyColumnArray(), column);
}
// ***** foreignKeys
public Iterable<ForeignKey> getForeignKeys() {
return new ArrayIterable<ForeignKey>(this.getForeignKeyArray());
}
private synchronized DTPForeignKeyWrapper[] getForeignKeyArray() {
if (this.foreignKeys == null) {
this.foreignKeys = this.buildForeignKeyArray();
}
return this.foreignKeys;
}
private DTPForeignKeyWrapper[] buildForeignKeyArray() {
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 getForeignKeysSize() {
return this.getForeignKeyArray().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.getForeignKeyArray()) {
if (fkWrapper.baseColumnsContains(column)) {
return true;
}
}
return false;
}
// ***** join table
public boolean isPossibleJoinTable() {
if (this.getForeignKeyArray().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 <code>FOO_BAR</code>
* and it joins tables <code>FOO</code> and <code>BAR</code>,
* return the foreign key to <code>FOO</code>;
* if the table name is <code>BAR_FOO</code>
* and it joins tables <code>FOO</code> and <code>BAR</code>,
* return the foreign key to <code>BAR</code>;
* otherwise simply return the first foreign key in the array.
*/
public ForeignKey getJoinTableOwningForeignKey() {
ForeignKey fk0 = this.getForeignKeyArray()[0];
String name0 = fk0.getReferencedTable().getName();
ForeignKey fk1 = this.getForeignKeyArray()[1];
String name1 = fk1.getReferencedTable().getName();
return this.getName().equals(name1 + '_' + name0) ? fk1 : fk0;
}
public ForeignKey getJoinTableNonOwningForeignKey() {
ForeignKey fk0 = this.getForeignKeyArray()[0];
ForeignKey fk1 = this.getForeignKeyArray()[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();
}
// ********** 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
synchronized 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;
}
}