Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.jumpmind.db.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.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Represents the database model, ie. the tables in the database. It also
* contains the corresponding dyna classes for creating dyna beans for the
* objects stored in the tables.
*/
public class Database implements Serializable, Cloneable {
protected static final Logger log = LoggerFactory.getLogger(Database.class);
/** Unique ID for serialization purposes. */
private static final long serialVersionUID = -3160443396757573868L;
/** The name of the database model. */
private String name;
/** The method for generating primary keys (currently ignored). */
private String idMethod;
/** The version of the model. */
private String version;
/** The tables. */
private ArrayList
tables = new ArrayList
();
private Map tableIndexCache = new HashMap();
public static Table[] sortByForeignKeys(Table... tables) {
if (tables != null) {
List
list = new ArrayList
(tables.length);
for (Table table : tables) {
list.add(table);
}
list = sortByForeignKeys(list);
tables = list.toArray(new Table[list.size()]);
}
return tables;
}
/**
* Implements modified topological sort of tables (@see topological
* sorting). The 'depth-first search' is implemented in order to detect
* and ignore cycles.
*
* @param tables
* List of tables to sort.
* @return List of tables in their dependency order - if table A has a
* foreign key for table B then table B will precede table A in the
* list.
*/
public static List
sortByForeignKeys(List
tables) {
List
sorted = new ArrayList
(tables.size());
List
visited = new ArrayList
(tables.size());
List
stack = new ArrayList
();
Map tableMap = new HashMap();
for (int i = 0; i < tables.size(); i++) {
tableMap.put(tables.get(i).getName(), tables.get(i));
}
for (int i = 0; i < tables.size(); i++) {
sortByForegnKeysVisit(tables.get(i), tableMap, sorted, visited, stack);
}
return sorted;
}
private static void sortByForegnKeysVisit(Table table, Map tableMap,
List
sorted, List
visited, List
stack) {
if (visited.contains(table)) {
return;
}
if (stack.contains(table)) {
return;
} // cycle detected - ignore this FK
visited.add(table);
stack.add(table);
for (ForeignKey fk : table.getForeignKeys()) {
Table foreignTable = tableMap.get(fk.getForeignTableName());
if (foreignTable != null) { // ignore foreign keys to tables outside
// of the input set
sortByForegnKeysVisit(foreignTable, tableMap, sorted, visited, stack);
}
}
sorted.add(table);
stack.remove(stack.size() - 1);
}
/**
* Adds all tables from the other database to this database. Note that the
* other database is not changed.
*
* @param otherDb
* The other database model
*/
public void mergeWith(Database otherDb) throws ModelException {
for (Iterator
it = otherDb.tables.iterator(); it.hasNext();) {
Table table = (Table) it.next();
if (findTable(table.getName()) != null) {
// TODO: It might make more sense to log a warning and overwrite
// the table (or merge them) ?
throw new ModelException("Cannot merge the models because table " + table.getName()
+ " already defined in this model");
}
try {
addTable((Table) table.clone());
} catch (CloneNotSupportedException ex) {
// won't happen
}
}
}
/**
* Returns the name of this database model.
*
* @return The name
*/
public String getName() {
return name;
}
/**
* Sets the name of this database model.
*
* @param name
* The name
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the version of this database model.
*
* @return The version
*/
public String getVersion() {
return version;
}
/**
* Sets the version of this database model.
*
* @param version
* The version
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Returns the method for generating primary key values.
*
* @return The method
*/
public String getIdMethod() {
return idMethod;
}
/**
* Sets the method for generating primary key values. Note that this value
* is ignored by DdlUtils and only for compatibility with Torque.
*
* @param idMethod
* The method
*/
public void setIdMethod(String idMethod) {
this.idMethod = idMethod;
}
/**
* Returns the number of tables in this model.
*
* @return The number of tables
*/
public int getTableCount() {
return tables.size();
}
/**
* Returns the tables in this model.
*
* @return The tables
*/
public Table[] getTables() {
return (Table[]) tables.toArray(new Table[tables.size()]);
}
/**
* Returns the table at the specified position.
*
* @param idx
* The index of the table
* @return The table
*/
public Table getTable(int idx) {
return (Table) tables.get(idx);
}
/**
* Adds a table.
*
* @param table
* The table to add
*/
public void addTable(Table table) {
if (table != null) {
tables.add(table);
}
}
/**
* Adds a table at the specified position.
*
* @param idx
* The index where to insert the table
* @param table
* The table to add
*/
public void addTable(int idx, Table table) {
if (table != null) {
tables.add(idx, table);
}
}
/**
* Adds the given tables.
*
* @param tables
* The tables to add
*/
public void addTables(Collection
tables) {
for (Iterator
it = tables.iterator(); it.hasNext();) {
addTable((Table) it.next());
}
}
public void addTables(Table[] tables) {
for (Table table : tables) {
addTable(table);
}
}
/**
* Removes the given table.
*
* @param table
* The table to remove
*/
public void removeTable(Table table) {
if (table != null) {
tables.remove(table);
}
}
/**
* Removes the indicated table.
*
* @param idx
* The index of the table to remove
*/
public void removeTable(int idx) {
tables.remove(idx);
}
// Helper methods
/**
* Initializes the model by establishing the relationships between elements
* in this model encoded eg. in foreign keys etc. Also checks that the model
* elements are valid (table and columns have a name, foreign keys rference
* existing tables etc.)
*/
public void initialize() throws ModelException {
// we have to setup
// * target tables in foreign keys
// * columns in foreign key references
// * columns in indices
// * columns in uniques
HashSet namesOfProcessedTables = new HashSet();
HashSet namesOfProcessedColumns = new HashSet();
HashSet namesOfProcessedFks = new HashSet();
HashSet namesOfProcessedIndices = new HashSet();
int tableIdx = 0;
for (Iterator
tableIt = tables.iterator(); tableIt.hasNext(); tableIdx++) {
Table curTable = tableIt.next();
if ((curTable.getName() == null) || (curTable.getName().length() == 0)) {
throw new ModelException("The table nr. " + tableIdx + " has no name");
}
if (namesOfProcessedTables.contains(curTable.getFullyQualifiedTableName())) {
throw new ModelException("There are multiple tables with the name "
+ curTable.getName());
}
namesOfProcessedTables.add(curTable.getFullyQualifiedTableName());
namesOfProcessedColumns.clear();
namesOfProcessedFks.clear();
namesOfProcessedIndices.clear();
for (int idx = 0; idx < curTable.getColumnCount(); idx++) {
Column column = curTable.getColumn(idx);
if ((column.getName() == null) || (column.getName().length() == 0)) {
throw new ModelException("The column nr. " + idx + " in table "
+ curTable.getName() + " has no name");
}
if (namesOfProcessedColumns.contains(column.getName())) {
throw new ModelException("There are multiple column with the name "
+ column.getName() + " in the table " + curTable.getName());
}
namesOfProcessedColumns.add(column.getName());
if ((column.getMappedType() == null) || (column.getMappedType().length() == 0)) {
throw new ModelException("The column nr. " + idx + " in table "
+ curTable.getName() + " has no type");
}
if ((column.getMappedTypeCode() == Types.OTHER)
&& !"OTHER".equalsIgnoreCase(column.getMappedType())) {
throw new ModelException("The column nr. " + idx + " in table "
+ curTable.getName() + " has an unknown type " + column.getMappedType());
}
namesOfProcessedColumns.add(column.getName());
}
for (int idx = 0; idx < curTable.getForeignKeyCount(); idx++) {
ForeignKey fk = curTable.getForeignKey(idx);
String fkName = (fk.getName() == null ? "" : fk.getName());
String fkDesc = (fkName.length() == 0 ? "nr. " + idx : fkName);
if (fkName.length() > 0) {
if (namesOfProcessedFks.contains(fkName)) {
throw new ModelException("There are multiple foreign keys in table "
+ curTable.getName() + " with the name " + fkName);
}
namesOfProcessedFks.add(fkName);
}
if (fk.getForeignTable() == null) {
Table targetTable = findTable(fk.getForeignTableName(), true);
if (targetTable != null) {
fk.setForeignTable(targetTable);
} else {
log.debug("The foreignkey "
+ fkDesc
+ " in table "
+ curTable.getName()
+ " references the undefined table "
+ fk.getForeignTableName()
+ ". This could be because the foreign key table was in another schema which is a bug that should be fixed in the future.");
}
}
if (fk.getForeignTable() != null) {
for (int refIdx = 0; refIdx < fk.getReferenceCount(); refIdx++) {
Reference ref = fk.getReference(refIdx);
if (ref.getLocalColumn() == null) {
Column localColumn = curTable
.findColumn(ref.getLocalColumnName(), true);
if (localColumn == null) {
throw new ModelException("The foreignkey " + fkDesc + " in table "
+ curTable.getName()
+ " references the undefined local column "
+ ref.getLocalColumnName());
} else {
ref.setLocalColumn(localColumn);
}
}
if (ref.getForeignColumn() == null) {
Column foreignColumn = fk.getForeignTable().findColumn(
ref.getForeignColumnName(), true);
if (foreignColumn == null) {
throw new ModelException("The foreignkey " + fkDesc + " in table "
+ curTable.getName()
+ " references the undefined local column "
+ ref.getForeignColumnName() + " in table "
+ fk.getForeignTable().getName());
} else {
ref.setForeignColumn(foreignColumn);
}
}
}
}
}
for (int idx = 0; idx < curTable.getIndexCount(); idx++) {
IIndex index = curTable.getIndex(idx);
String indexName = (index.getName() == null ? "" : index.getName());
if (indexName.length() > 0) {
if (namesOfProcessedIndices.contains(indexName)) {
throw new ModelException("There are multiple indices in table "
+ curTable.getName() + " with the name " + indexName);
}
namesOfProcessedIndices.add(indexName);
}
for (int indexColumnIdx = 0; indexColumnIdx < index.getColumnCount(); indexColumnIdx++) {
IndexColumn indexColumn = index.getColumn(indexColumnIdx);
Column column = curTable.findColumn(indexColumn.getName(), true);
indexColumn.setColumn(column);
}
}
}
}
/**
* Finds the table with the specified name, using case insensitive matching.
* Note that this method is not called getTable to avoid introspection
* problems.
*
* @param name
* The name of the table to find
* @return The table or null if there is no such table
*/
public Table findTable(String name) {
return findTable(name, false);
}
/**
* Finds the table with the specified name, using case insensitive matching.
* Note that this method is not called getTable) to avoid introspection
* problems.
*
* @param name
* The name of the table to find
* @param caseSensitive
* Whether case matters for the names
* @return The table or null if there is no such table
*/
public Table findTable(String name, boolean caseSensitive) {
for (Iterator