/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.metamodels.relational.provider; import java.util.ArrayList; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.association.AbstractAssociationDescriptor; import org.teiid.designer.metamodels.relational.BaseTable; import org.teiid.designer.metamodels.relational.ForeignKey; import org.teiid.designer.metamodels.relational.PrimaryKey; import org.teiid.designer.metamodels.relational.RelationalFactory; import org.teiid.designer.metamodels.relational.RelationalPlugin; import org.teiid.designer.metamodels.relational.Table; /** * ForeignKeyAssociationDescriptor * * @since 8.0 */ public class ForeignKeyAssociationDescriptor extends AbstractAssociationDescriptor { private static final String TYPE = "ForeignKeyAssociation"; //$NON-NLS-1$ private static final String LABEL = RelationalPlugin.Util.getString("ForeignKeyAssociationDescriptor.Foreign_Key_Association_1"); //$NON-NLS-1$ private static final String NEW = RelationalPlugin.Util.getString("ForeignKeyAssociationDescriptor.New_1"); //$NON-NLS-1$ private boolean overwritePkRef; private String text; // ================================================================================== // C O N S T R U C T O R S // ================================================================================== /** * Construct an instance of ForeignKeyAssociationDescriptor. * * @param eObjects */ public ForeignKeyAssociationDescriptor( List eObjects ) { super(eObjects); this.overwritePkRef = true; this.text = LABEL; } // ================================================================================== // I N T E R F A C E M E T H O D S // ================================================================================== /* (non-Javadoc) * @See org.teiid.designer.core.association.AssociationDescriptor#getType() */ @Override public String getType() { return TYPE; } /* (non-Javadoc) * @See org.teiid.designer.core.association.AssociationDescriptor#isComplete() */ @Override public boolean isComplete() { final List eObjects = this.getEObjects(); if (eObjects == null || eObjects.isEmpty()) { return false; } // Return false if the list contains invalid objects if (!ForeignKeyAssociationProvider.containsValidObjects(eObjects, ForeignKeyAssociationProvider.VALID_CLASSES_TYPES)) { return false; } // Return false if there are not two tables implicitly or explicitly defined in the list final List tables = ForeignKeyAssociationProvider.getTables(eObjects); if (tables.size() != 2) { return false; } // ---------------------------------------- // Check the contents of the selection list // ---------------------------------------- final Table tableA = (Table)tables.get(0); final Table tableB = (Table)tables.get(1); // Return false if there are two primary keys in the selection list final PrimaryKey pkA = ForeignKeyAssociationProvider.getPrimaryKey(eObjects, tableA); final PrimaryKey pkB = ForeignKeyAssociationProvider.getPrimaryKey(eObjects, tableB); if (pkA != null && pkB != null) { return false; } // Return false if there are two foreign keys in the selection list, // either in different tables or within the same table final List fKeysA = ForeignKeyAssociationProvider.getForeignKeys(eObjects, tableA); final List fKeysB = ForeignKeyAssociationProvider.getForeignKeys(eObjects, tableB); if (!fKeysA.isEmpty() && !fKeysB.isEmpty()) { return false; } if (fKeysA.size() > 1 || fKeysB.size() > 1) { return false; } return true; } /* (non-Javadoc) * @See org.teiid.designer.core.association.AssociationDescriptor#getImage() */ @Override public Object getImage() { return RelationalEditPlugin.INSTANCE.getImage("full/obj16/ForeignKey"); //$NON-NLS-1$ } /* (non-Javadoc) * @See org.teiid.designer.core.association.AssociationDescriptor#getText() */ @Override public String getText() { return this.text; } /* (non-Javadoc) * @see org.teiid.designer.core.association.AbstractAssociationDescriptor#canCreate() */ @Override public boolean canCreate() { // NO_UCD final List eObjects = this.getEObjects(); return ForeignKeyAssociationProvider.containsValidObjects(eObjects, ForeignKeyAssociationProvider.VALID_CLASSES_TYPES); } /* (non-Javadoc) * @see org.teiid.designer.core.association.AbstractAssociationDescriptor#execute() */ @Override public EObject create() { if (!isComplete()) { return null; } // Order the list of selected objects into a PrimaryKey -> ForeignKey order final List eObjects = this.getEObjects(); final List selectedObjs = getOrderedObjects(eObjects); // Create the ForeignKey relationship ... final List tables = ForeignKeyAssociationProvider.getTables(selectedObjs); final BaseTable pkTable = (BaseTable)tables.get(0); final BaseTable fkTable = (BaseTable)tables.get(1); return createAssociation(pkTable, fkTable, selectedObjs, overwritePkRef); } // ================================================================================== // P R O T E C T E D M E T H O D S // ================================================================================== /* * Return the ordered list of selected objects. The ordered list is found by first * placing all entries associated with each table in their own list. The next step * is to determine which of the two lists contains the primary key to be used as the * source for the assocation. This list is placed at the top of the resulting * list while the foreign key portion is added to the bottom of the resulting list. */ protected List getOrderedObjects( final List eObjects ) { final List tables = ForeignKeyAssociationProvider.getTables(eObjects); final BaseTable tableA = (BaseTable)tables.get(0); final BaseTable tableB = (BaseTable)tables.get(1); final PrimaryKey pkA = ForeignKeyAssociationProvider.getPrimaryKey(eObjects, tableA); final PrimaryKey pkB = ForeignKeyAssociationProvider.getPrimaryKey(eObjects, tableB); final List fKeysA = ForeignKeyAssociationProvider.getForeignKeys(eObjects, tableA); final List fKeysB = ForeignKeyAssociationProvider.getForeignKeys(eObjects, tableB); final List columnsA = ForeignKeyAssociationProvider.getColumns(eObjects, tableA); final List columnsB = ForeignKeyAssociationProvider.getColumns(eObjects, tableB); // If the selection list contains a PrimaryKey reference .... boolean sortFromAtoB = true; boolean orderIsSet = false; if (pkB != null) { sortFromAtoB = false; orderIsSet = true; } // If the selection list contains a ForeignKey reference .... if (!fKeysA.isEmpty() && !orderIsSet) { sortFromAtoB = false; orderIsSet = true; } // If one table already has a primary key and the other does not ... if (tableA.getPrimaryKey() == null && tableB.getPrimaryKey() != null && !orderIsSet) { sortFromAtoB = false; orderIsSet = true; } final List result = new ArrayList(eObjects.size() + 2); if (sortFromAtoB) { result.add(tableA); result.add(pkA); result.addAll(columnsA); result.addAll(fKeysA); result.add(tableB); result.add(pkB); result.addAll(columnsB); result.addAll(fKeysB); } else { result.add(tableB); result.add(pkB); result.addAll(columnsB); result.addAll(fKeysB); result.add(tableA); result.add(pkA); result.addAll(columnsA); result.addAll(fKeysA); } return result; } /** * Create the foreign key relationship between the defined * * @param pkTable the table for the primary key end * @param fkTable the table for the foreign key end * @param selectedObjs the list of selected objects * @param resetPkRefOnFk if true, the primary key reference on any existing foreign key that participates in this association * will be reset. * @return the ForeignKey instance * @throws ModelerCoreException */ protected EObject createAssociation( final BaseTable pkTable, final BaseTable fkTable, final List selectedObjs, boolean resetPkRefOnFk ) { CoreArgCheck.isNotNull(pkTable); CoreArgCheck.isNotNull(fkTable); // ----------------------------------------------- // Process the primary key part of the association // ----------------------------------------------- // Get the columns from the selection list associated with the source table List pkColumns = ForeignKeyAssociationProvider.getColumns(selectedObjs, pkTable); PrimaryKey pk = pkTable.getPrimaryKey(); // If there is no PrimaryKey under the source table then create one if (pk == null) { pk = RelationalFactory.eINSTANCE.createPrimaryKey(); pk.setTable(pkTable); pk.setName(NEW + pk.eClass().getName()); } // Add any columns for the source to the primary key if (!pkColumns.isEmpty() && pk.getColumns().isEmpty()) { pk.getColumns().addAll(pkColumns); } // ------------------------------------------ // Process the target part of the association // ------------------------------------------ // Get the columns and foreign keys from the selection list associated with the target table List fkColumns = ForeignKeyAssociationProvider.getColumns(selectedObjs, fkTable); List fkeys = ForeignKeyAssociationProvider.getForeignKeys(selectedObjs, fkTable); ForeignKey fk = null; // If there is no ForeignKey in the selection list then create one if (fkeys.isEmpty()) { fk = RelationalFactory.eINSTANCE.createForeignKey(); fk.setTable(fkTable); fk.setUniqueKey(pk); } // There is a ForeignKey in the selection list else { fk = (ForeignKey)fkeys.get(0); if (resetPkRefOnFk) { fk.setUniqueKey(pk); } } // Add any columns for the target to the foreign key if (!fkColumns.isEmpty() && fk.getColumns().isEmpty()) { fk.getColumns().addAll(fkColumns); } return fk; } /** * @param string */ protected void setText( String string ) { this.text = string; } /** * @param b */ protected void setOverwritePkRef( boolean b ) { this.overwritePkRef = b; } }