/******************************************************************************* * 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.gen.internal.old; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Set; 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.NameTools; import org.eclipse.jpt.utility.internal.StringTools; import org.eclipse.jpt.utility.internal.iterators.FilteringIterator; /** * associate a table with the various relations that will be used when * generating the entity corresponding to the table */ class GenTable { private final GenScope scope; private final Table table; // these relations cannot be built until after we have built all the scope's tables private ManyToManyRelation joinTableRelation; private final ArrayList ownedManyToManyRelations = new ArrayList(); private final ArrayList nonOwnedManyToManyRelations = new ArrayList(); private final ArrayList manyToOneRelations = new ArrayList(); private final ArrayList oneToManyRelations = new ArrayList(); private final HashSet foreignKeyColumns = new HashSet(); private final HashSet attributeNames = new HashSet(); private String attributeNameForEmbeddedId; private final HashMap basicAttributeNames = new HashMap(); private final HashMap manyToOneAttributeNames = new HashMap(); private final HashMap oneToManyAttributeNames = new HashMap(); private final HashMap ownedManyToManyAttributeNames = new HashMap(); private final HashMap nonOwnedManyToManyAttributeNames = new HashMap(); // ********** construction/initialization ********** GenTable(GenScope scope, Table table) { super(); this.scope = scope; this.table = table; } // ********** package API ********** EntityGenerator.Config getEntityConfig() { return this.scope.getEntityConfig(); } /** * examples: * GenTable(FOO) => "FOO_COLLECTION" * GenTable(foo) => "fooCollection" * GenTable(Foo) => "FooCollection" */ String getCollectionAttributeName() { String name = this.getName(); String suffix = this.getEntityConfig().getCollectionAttributeNameSuffix(); if (StringTools.stringIsUppercase(name)) { // hmmm ~bjv suffix = '_' + suffix.toUpperCase(); } return name + suffix; } /** * determine whether the table is a "join" table within the table's scope; * this can be removed, later, if we find another table references the, * seemingly, join table * @see #clearJoinTableRelation() (and callers) */ void buildJoinTableRelation() { if ( ! this.table.isPossibleJoinTable()) { return; // the table must have exactly 2 foreign keys } ForeignKey owningFK = this.table.getJoinTableOwningForeignKey(); GenTable owningGenTable = this.scope.getGenTable(owningFK.getReferencedTable()); if (owningGenTable == null) { return; // both tables must be in the scope } ForeignKey nonOwningFK = this.table.getJoinTableNonOwningForeignKey(); GenTable nonOwningGenTable = this.scope.getGenTable(nonOwningFK.getReferencedTable()); if (nonOwningGenTable == null) { return; // both tables must be in the scope } this.joinTableRelation = new ManyToManyRelation( this, owningFK, owningGenTable, nonOwningFK, nonOwningGenTable ); } /** * used by the scope to figure out whether "join" tables should be * converted to "entity" tables */ void addReferencedGenTablesTo(Set referencedTables) { for (Iterator stream = this.table.foreignKeys(); stream.hasNext(); ) { ForeignKey fk = stream.next(); GenTable genTable = this.scope.getGenTable(fk.getReferencedTable()); if (genTable != null) { referencedTables.add(genTable); } } } /** * the scope clears the join table relation if there are any references * to the join table from other tables in the scope */ void clearJoinTableRelation() { this.joinTableRelation.clear(); this.joinTableRelation = null; } /** * find "in-scope" foreign keys */ void buildManyToOneRelations() { for (Iterator stream = this.table.foreignKeys(); stream.hasNext(); ) { ForeignKey fk = stream.next(); GenTable referencedGenTable = this.scope.getGenTable(fk.getReferencedTable()); if (referencedGenTable != null) { this.manyToOneRelations.add(new ManyToOneRelation(this, fk, referencedGenTable)); } } } /** * now that all the relations are in place, we can configure the Java * attribute names */ void buildAttributeNames() { this.buildAttributeNameForEmbeddedId(); // gather up all the table's columns... Set columns = CollectionTools.set(this.table.columns(), this.table.columnsSize()); // ...remove the columns that belong exclusively to many-to-one foreign keys... this.buildManyToOneAttributeNames(columns); // ...and use the remaining columns to generate "basic" attribute names this.buildBasicAttributeNames(columns); this.buildOneToManyAttributeNames(); this.buildOwnedManyToManyAttributeNames(); this.buildNonOwnedManyToManyAttributeNames(); } /** * return the columns that are part of the table's primary key * but are also part of an "in-scope" foreign key */ Iterator readOnlyPrimaryKeyColumns() { return new FilteringIterator(this.table.primaryKeyColumns()) { @Override protected boolean accept(Column pkColumn) { return pkColumn.isPartOfForeignKey(); } }; } /** * return the columns that are part of the table's primary key * but are NOT part of any "in-scope" foreign key */ Iterator writablePrimaryKeyColumns() { return new FilteringIterator(this.table.primaryKeyColumns()) { @Override protected boolean accept(Column pkColumn) { return ! pkColumn.isPartOfForeignKey(); } }; } /** * return the columns that NEITHER part of the table's primary key * NOR part of any foreign key */ Iterator nonPrimaryKeyBasicColumns() { return new FilteringIterator(this.table.columns()) { @Override protected boolean accept(Column column) { return ! (column.isPartOfPrimaryKey() || column.isPartOfForeignKey()); } }; } Table getTable() { return this.table; } String getEntityName() { return this.getEntityConfig().getEntityName(this.table); } boolean isJoinTable() { return this.joinTableRelation != null; } void addOwnedManyToManyRelation(ManyToManyRelation relation) { this.ownedManyToManyRelations.add(relation); } void removeOwnedManyToManyRelation(ManyToManyRelation relation) { this.ownedManyToManyRelations.remove(relation); } void addNonOwnedManyToManyRelation(ManyToManyRelation relation) { this.nonOwnedManyToManyRelations.add(relation); } void removeNonOwnedManyToManyRelation(ManyToManyRelation relation) { this.nonOwnedManyToManyRelations.remove(relation); } void addOneToManyRelation(OneToManyRelation relation) { this.oneToManyRelations.add(relation); } Iterator manyToOneRelations() { return this.manyToOneRelations.iterator(); } Iterator oneToManyRelations() { return this.oneToManyRelations.iterator(); } Iterator ownedManyToManyRelations() { return this.ownedManyToManyRelations.iterator(); } Iterator nonOwnedManyToManyRelations() { return this.nonOwnedManyToManyRelations.iterator(); } /** * this will return null if we don't want an embedded id attribute */ String getAttributeNameForEmbeddedId() { return this.attributeNameForEmbeddedId; } String getAttributeNameFor(Column column) { return this.basicAttributeNames.get(column); } String getAttributeNameFor(ManyToOneRelation relation) { return this.manyToOneAttributeNames.get(relation); } String getAttributeNameFor(OneToManyRelation relation) { return this.oneToManyAttributeNames.get(relation); } String getAttributeNameForOwned(ManyToManyRelation relation) { return this.ownedManyToManyAttributeNames.get(relation); } String getAttributeNameForNonOwned(ManyToManyRelation relation) { return this.nonOwnedManyToManyAttributeNames.get(relation); } String getName() { return this.table.getName(); } boolean joinTableNameIsDefault() { return this.table.joinTableNameIsDefault(); } // ********** internal API ********** /** * if we are going to generate an EmbeddedId attribute, add its name to * 'attributeNames' so we don't collide with it later, when generating * attribute names for the columns etc. */ private void buildAttributeNameForEmbeddedId() { if ((this.table.primaryKeyColumnsSize() > 1) && this.getEntityConfig().generateEmbeddedIdForCompoundPK()) { this.attributeNameForEmbeddedId = this.configureAttributeName(this.getEntityConfig().getEmbeddedIdAttributeName()); } } /** * While we are figuring out the names for the m:1 attributes, remove from the * specified set of columns the columns that are only part of the foreign keys * (leaving the remaining columns for basic attributes). * Store the calculated names so we can get them back later, when we * are generating source. */ private void buildManyToOneAttributeNames(Set columns) { for (ManyToOneRelation relation : this.manyToOneRelations) { CollectionTools.removeAll(columns, relation.getForeignKey().nonPrimaryKeyBaseColumns()); CollectionTools.addAll(this.foreignKeyColumns, relation.getForeignKey().baseColumns()); String attributeName = this.configureAttributeName(relation.getAttributeName()); relation.setMappedBy(attributeName); this.manyToOneAttributeNames.put(relation, attributeName); } } /** * Build a unique attribute name for the specified "basic" columns, * checking for name collisions. * Store the calculated names so we can get them back later, when we * are generating source. */ private void buildBasicAttributeNames(Set columns) { for (Column column : columns) { String attributeName = this.configureAttributeName(column.getName()); this.basicAttributeNames.put(column, attributeName); } } private void buildOneToManyAttributeNames() { for (OneToManyRelation relation : this.oneToManyRelations) { String attributeName = this.configureAttributeName(relation.getAttributeName()); this.oneToManyAttributeNames.put(relation, attributeName); } } private void buildOwnedManyToManyAttributeNames() { for (ManyToManyRelation relation : this.ownedManyToManyRelations) { String attributeName = this.configureAttributeName(relation.getOwnedAttributeName()); relation.setMappedBy(attributeName); this.ownedManyToManyAttributeNames.put(relation, attributeName); } } private void buildNonOwnedManyToManyAttributeNames() { for (ManyToManyRelation relation : this.nonOwnedManyToManyRelations) { String attributeName = this.configureAttributeName(relation.getNonOwnedAttributeName()); this.nonOwnedManyToManyAttributeNames.put(relation, attributeName); } } /** * Convert the specified attribute name to something unique for the entity, * converting it to something Java-like if the config flag is set. * Store the calculated name to prevent future name collisions. */ private String configureAttributeName(String attributeName) { String result = attributeName; if (this.getEntityConfig().convertToJavaStyleIdentifiers()) { result = EntityGenTools.convertToUniqueJavaStyleAttributeName(result, this.attributeNames); } else { // first, convert the attribute name to a legal Java identifier result = NameTools.convertToJavaIdentifier(result); // then make sure it's unique result = NameTools.uniqueNameForIgnoreCase(attributeName, this.attributeNames); } this.attributeNames.add(result); return result; } @Override public String toString() { return StringTools.buildToStringFor(this, this.table); } }