/* * 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.transformation.ui.util; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EventObject; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.edit.provider.INotifyChangedListener; import org.eclipse.emf.mapping.MappingHelper; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.widgets.Display; import org.teiid.core.designer.event.EventObjectListener; import org.teiid.core.designer.event.EventSourceException; import org.teiid.designer.core.ModelerCore; import org.teiid.designer.core.notification.util.NotificationUtilities; import org.teiid.designer.core.query.QueryValidationResult; import org.teiid.designer.core.query.QueryValidator; import org.teiid.designer.core.resource.EmfResource; import org.teiid.designer.core.transaction.SourcedNotification; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.core.workspace.ModelWorkspaceManager; import org.teiid.designer.core.workspace.ModelWorkspaceNotification; import org.teiid.designer.core.workspace.ModelWorkspaceNotificationListener; import org.teiid.designer.diagram.ui.util.DiagramUiUtilities; import org.teiid.designer.metamodels.core.ModelAnnotation; import org.teiid.designer.metamodels.function.ScalarFunction; import org.teiid.designer.metamodels.relational.ProcedureParameter; import org.teiid.designer.metamodels.relational.Table; import org.teiid.designer.metamodels.transformation.SqlAlias; import org.teiid.designer.metamodels.transformation.SqlTransformation; import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot; import org.teiid.designer.metamodels.transformation.TransformationPackage; import org.teiid.designer.query.sql.lang.ICommand; import org.teiid.designer.query.sql.lang.IQuery; import org.teiid.designer.query.sql.lang.IQueryCommand; import org.teiid.designer.query.sql.lang.ISelect; import org.teiid.designer.transformation.TransformationPlugin; import org.teiid.designer.transformation.ui.PluginConstants; import org.teiid.designer.transformation.ui.UiConstants; import org.teiid.designer.transformation.ui.UiPlugin; import org.teiid.designer.transformation.ui.actions.ITransformationDiagramActionConstants; import org.teiid.designer.transformation.ui.actions.ImportTransformationSqlFromTextAction; import org.teiid.designer.transformation.ui.actions.ReconcileTransformationAction; import org.teiid.designer.transformation.ui.editors.TransformationObjectEditorPage; import org.teiid.designer.transformation.ui.editors.sqleditor.SqlEditorPanel; import org.teiid.designer.transformation.util.AttributeMappingHelper; import org.teiid.designer.transformation.util.SqlMappingRootCache; import org.teiid.designer.transformation.util.TransformationHelper; import org.teiid.designer.transformation.util.TransformationMappingHelper; import org.teiid.designer.transformation.util.TransformationSqlHelper; import org.teiid.designer.transformation.validation.TransformationValidator; import org.teiid.designer.ui.common.dialog.RadioMessageDialog; import org.teiid.designer.ui.common.util.UiUtil; import org.teiid.designer.ui.editors.ModelEditor; import org.teiid.designer.ui.editors.ModelEditorManager; import org.teiid.designer.ui.editors.ModelObjectEditorPage; import org.teiid.designer.ui.event.ModelResourceEvent; import org.teiid.designer.ui.refactor.rename.RenameRefactorAction; import org.teiid.designer.ui.undo.ModelerUndoManager; import org.teiid.designer.ui.viewsupport.ModelIdentifier; import org.teiid.designer.ui.viewsupport.ModelUtilities; /** * TransformationNotificationListener The notification listener is instantiated upon initialization of the plugin, and registered * as a Notification listener. The listener responds to the following notifications SqlTransformation o SQL strings changed - the * listener will use the SQlTransformationHelper to reconcile the target attributes to the sql. o SqlAlias added or removed - the * listener will use the SqlTransformationHelper to modify the SqlTransformation SQL strings SqlTable o Children added/removed - * respond to addition or removal of children (Sql Columns). o rename - responds to table rename SqlColumn o Change - responds to * changes to the Column (eg rename). * * @since 8.0 */ public class TransformationNotificationListener implements INotifyChangedListener, EventObjectListener, UiConstants { static final String ADD_SQL_ELEM_GRP_REFS_TITLE = UiConstants.Util.getString("TransformationNotificationListener.addSQLElemGrpAttrsTitle"); //$NON-NLS-1$ static final String REMOVE_SQL_ELEM_GRP_REFS_TITLE = UiConstants.Util.getString("TransformationNotificationListener.removeSQLElemGrpRefsTitle"); //$NON-NLS-1$ static final String REMOVE_SQL_ELEMS_TITLE = UiConstants.Util.getString("TransformationNotificationListener.removeSQLElemsTitle"); //$NON-NLS-1$ static final String REMOVE_SQL_ELEMS_MSG = UiConstants.Util.getString("TransformationNotificationListener.removeSQLElemsMsg"); //$NON-NLS-1$ private static final String DEFAULT_REMOVED_SOURCE = UiConstants.Util.getString("TransformationNotificationListener.defaultRemovedSource"); //$NON-NLS-1$ private static final String DEFAULT_ADDED_SOURCE = UiConstants.Util.getString("TransformationNotificationListener.defaultAddedSource"); //$NON-NLS-1$ static final String SAVE_BEFORE_CHANGE_TITLE = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesTitle"); //$NON-NLS-1$ // SBC == SAVE_BEFORE_CHANGE static final String SBC_GROUP_TITLE = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesRadioTitle"); //$NON-NLS-1$ private static final String SBC_RADIO_SAVE = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesRadioButtonSave"); //$NON-NLS-1$ private static final String SBC_RADIO_IGNORE = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesRadioButtonIgnore"); //$NON-NLS-1$ private static final String SBC_RADIO_HALT = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesRadioButtonHalt"); //$NON-NLS-1$ private static final String SBC_NOTE = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesNote"); //$NON-NLS-1$ private static final boolean NOT_SIGNIFICANT = false; private static final boolean IS_UNDOABLE = true; private static final boolean NOT_UNDOABLE = false; static int uiIntegerResult = 0; static boolean uiBooleanResult = false; // Allow user to shut off notifications - defaults to false private boolean ignoreNotifications = false; private boolean ignoreTableSupportsUpdateChangedFalse = false; private boolean ignoreTableSupportsUpdateChangedTrue = false; boolean setColumnsUpdateableOnTableUpdateable = false; private IModelNotificationHandler functionHandler; /** * Construct an instance of TransformationNotificationListener. */ public TransformationNotificationListener() { super(); // add listener for workspace Project close and Model delete notifications WorkspaceNotificationListener listener = new WorkspaceNotificationListener(); ModelWorkspaceManager.getModelWorkspaceManager().addNotificationListener(listener); try { org.teiid.designer.ui.UiPlugin.getDefault().getEventBroker().addListener(ModelResourceEvent.class, this); } catch (EventSourceException e) { Util.log(IStatus.ERROR, e, e.getMessage()); } functionHandler = new FunctionModelNotificationHandler(); } public void setIgnoreNotifications( boolean shouldIgnore ) { this.ignoreNotifications = shouldIgnore; } /** * @see org.eclipse.emf.edit.provider.INotifyChangedListener#notifyChanged(org.eclipse.emf.common.notify.Notification) */ @Override public void notifyChanged( Notification notification ) { // If notifications are shut off, just return if (ignoreNotifications) return; // ---------------------------------------------------------------------------------------------- // NOTE: Transaction boundaries are taken care of by the specific handler. Dont start one here // ---------------------------------------------------------------------------------------------- // Check for SourcedNotification (we should only get SourcedNotifications) if (notification instanceof SourcedNotification) { if (sourceIsNotThis((SourcedNotification)notification) && sourceIsNotTransformationMappingHelper((SourcedNotification)notification)) { Object source = ((SourcedNotification)notification).getSource(); if (source == null) { source = notification.getNotifier(); } // Undos - special handler if (source instanceof ModelerUndoManager) { Collection notifications = ((SourcedNotification)notification).getNotifications(); handleUndo(notifications, source); } else { Collection notifications = ((SourcedNotification)notification).getNotifications(); handleNotifications(notifications, source); } } } else { // handle single Notification Collection notifications = new ArrayList(1); notifications.add(notification); handleNotifications(notifications, null); } } private boolean sourceIsNotTransformationMappingHelper( SourcedNotification sn ) { Object source = sn.getSource(); if (source instanceof TransformationMappingHelper) return false; return true; } private boolean sourceIsNotThis( SourcedNotification sn ) { Object source = sn.getSource(); if (source == null) return true; return !(sn.getSource().equals(this)); } /* * Notifications handler. Gathers all like notifications and handles them together. * Only the relevant notifications will be processed by this listener. * @param notifications the collection of all notifications */ private void handleNotifications( Collection notifications, Object source ) { // -------------------------------------------------------- // Do a first-pass - ignore irrelevant notifications // -------------------------------------------------------- Collection validNotifications = filterNotifications(notifications); Collection originalNotifications = new ArrayList(validNotifications); // ---------------------------------------- // Process remaining valid notifications // ---------------------------------------- if (!validNotifications.isEmpty()) { // --------------------------------------------- // SqlAliases Added to SqlTransformation // --------------------------------------------- Collection sqlAliasAdds = getSqlAliasAddNotifications(validNotifications); if (!sqlAliasAdds.isEmpty()) { handleSqlAliasAddNotifications(sqlAliasAdds, source); } // --------------------------------------------- // SqlAliases Removed from SqlTransformation // --------------------------------------------- Collection sqlAliasRemoves = getSqlAliasRemoveNotifications(validNotifications); if (!sqlAliasRemoves.isEmpty()) { handleSqlAliasRemoveNotifications(sqlAliasRemoves, source); } // --------------------------------------------- // SqlAliases Changed // --------------------------------------------- Collection sqlAliasChanges = getSqlAliasChangeNotifications(validNotifications); if (!sqlAliasChanges.isEmpty()) { handleSqlAliasChangeNotifications(sqlAliasChanges, source); } // --------------------------------------------- // Virtual Table Columns Added // --------------------------------------------- Collection virtualTableColAdds = getTargetVirtualTableColumnAddNotifications(validNotifications); if (!virtualTableColAdds.isEmpty()) { handleTargetVirtualTableColumnAddNotifications(virtualTableColAdds, source); } // --------------------------------------------- // Virtual Table Columns Removed // --------------------------------------------- Collection virtualTableColRemoves = getTargetVirtualTableColumnRemoveNotifications(validNotifications); if (!virtualTableColRemoves.isEmpty()) { handleTargetVirtualTableColumnRemoveNotifications(virtualTableColRemoves, source); } // --------------------------------------------- // Procedure ResultSet Columns Added // --------------------------------------------- Collection resultSetColAdds = getTargetProcedureResultSetColumnAddNotifications(validNotifications); if (!resultSetColAdds.isEmpty()) { handleTargetProcedureResultSetColumnAddNotifications(resultSetColAdds, source); } // --------------------------------------------- // Procedure ResultSet Columns Removed // --------------------------------------------- Collection resultSetColRemoves = getTargetProcedureResultSetColumnRemoveNotifications(validNotifications); if (!resultSetColRemoves.isEmpty()) { handleTargetProcedureResultSetColumnRemoveNotifications(resultSetColRemoves, source); } // --------------------------------------------- // Procedure ResultSet Added // --------------------------------------------- Collection resultSetAdds = getTargetProcedureResultSetOrParamAddNotifications(validNotifications); if (!resultSetAdds.isEmpty()) { handleTargetProcedureResultSetOrParamAddNotifications(resultSetAdds, source); } // Procedure Parameter Changed // --------------------------------------------- Collection procedParamChanges = getTargetProcedureParamChangeNotifications(validNotifications); if (!procedParamChanges.isEmpty()) { handleTargetProcedureParamChangeNotifications(procedParamChanges, source); } // --------------------------------------------- // Procedure ResultSet Removed // --------------------------------------------- Collection resultSetRemoves = getTargetProcedureResultSetOrParamRemoveNotifications(validNotifications); if (!resultSetRemoves.isEmpty()) { handleTargetProcedureResultSetOrParamRemoveNotifications(resultSetRemoves, source); } // ------------------------------------------------------- // SQL statements Changed - only process Select changes // ------------------------------------------------------- Collection sqlUIDStatementChanges = getSqlSelectUIDStatementChangeNotifications(validNotifications); if (!sqlUIDStatementChanges.isEmpty()) { handleSqlUIDStatementChangeNotifications(sqlUIDStatementChanges, source); } // ------------------------------------------------------- // Sql Table or Column renamed // ------------------------------------------------------- Collection tableOrColumnRenames = getSqlTableAndColumnRenameNotifications(validNotifications); if (!tableOrColumnRenames.isEmpty()) { handleSqlTableAndColumnRenameNotifications(tableOrColumnRenames, source); } // ------------------------------------------------------- // Sql Table or Column removed // ------------------------------------------------------- Collection tableOrColumnRemoves = getSqlTableAndColumnRemoveNotifications(validNotifications); if (!tableOrColumnRemoves.isEmpty()) { handleSqlTableAndColumnRemoveNotifications(tableOrColumnRemoves, source); } // --------------------------------------------- // Virtual Table Changed // --------------------------------------------- Collection virtualTableChanges = getTargetVirtualTableChangeNotifications(validNotifications); if (!virtualTableChanges.isEmpty()) { handleTargetVirtualTableChangeNotifications(virtualTableChanges, source); } // --------------------------------------------------------- // Sql Column Changed - handles attribute property changes // --------------------------------------------------------- Collection columnChanges = getSqlColumnChangeNotifications(validNotifications); if (!columnChanges.isEmpty()) { handleSqlColumnChangeNotifications(columnChanges, source); } // --------------------------------------------------------- // Sql Column Added // --------------------------------------------------------- Collection columnAdds = getSqlColumnAddNotifications(validNotifications); if (!columnAdds.isEmpty()) { handleSqlTableColumnAddNotifications(columnAdds, source); } // --------------------------------------------------------- // Model Refactor/Rename // This is fired as a mappingRoot change notification // with RenameRefactorAction as the source // --------------------------------------------------------- Collection modelRenames = getModelRenameNotifications(validNotifications, source); if (!modelRenames.isEmpty()) { handleModelRenameNotifications(modelRenames, source); } // --------------------------------------------------------- // Function Model Scalar Function or parameter changes // --------------------------------------------------------- functionHandler.handleNotifications(originalNotifications, source); } } /* * Do a first pass to filter out totally irrelevant notifications. Will only keep notifications * where one of the following has changed - 1) SqlTransformationMappingRoot, 2) SqlTransformation, * 3) SqlTable, 4) SqlColumn, 5)SqlProcedure, 6)SqlColumnSet - Virtual Proc ResultSet * @param notifications the collection of all notifications * @return new collection of relevant notifications */ private Collection filterNotifications( Collection notifications ) { Collection goodNotifications = new ArrayList(notifications.size()); Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // Get the object that changed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); // Only keep notifications where one of the following has changed: // 1) SqlTransformationMappingRoot // 2) SqlTransformation // 3) SqlTable // 4) SqlColumn // 5) SqlProcedure // 6) ColumnSet - Virtual Procedure ResultSet // 7) FunctionModel EObject if (changedObj != null && changedObj instanceof EObject && !DiagramUiUtilities.isDiagramObject((EObject)changedObj)) { if (changedObj instanceof SqlTransformation || changedObj instanceof SqlTransformationMappingRoot || TransformationHelper.isSqlTable(changedObj) || TransformationHelper.isSqlColumn(changedObj) || TransformationHelper.isSqlProcedure(changedObj) || TransformationHelper.isSqlProcedureParameter(changedObj) || TransformationHelper.isSqlColumnSet(changedObj) || functionHandler.shouldHandleChangedObject(changedObj)) { goodNotifications.add(notification); } else if (NotificationUtilities.isRemoved(notification)) { Object removedObj = notification.getOldValue(); if (TransformationHelper.isSqlTable(removedObj) || changedObj instanceof ModelAnnotation) { goodNotifications.add(notification); } } } else if( changedObj != null && changedObj instanceof EmfResource) { ModelResource mr = ModelUtilities.getModelResource((Resource)changedObj, false); if( ModelIdentifier.isFunctionModel(mr) ) { goodNotifications.add(notification); } } } return goodNotifications; } /* * Get all SqlAlias Add Notifications. * @param notifications the collection of all notifications * @return the SqlAlias Add Notifications */ private Collection getSqlAliasAddNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isAdded(notification)) { // Get the added children - check whether they are SqlAliases EObject[] newChildren = NotificationUtilities.getAddedChildren(notification); // If any of the added children are SqlAlias, add notification to result if (containsSqlAlias(newChildren)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all SqlAlias Remove Notifications. * @param notifications the collection of all notifications * @return the SqlAlias Remove Notifications */ private Collection getSqlAliasRemoveNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { // Get the removed children - check whether they are SqlAliases EObject[] removedChildren = NotificationUtilities.getRemovedChildren(notification); // If any of the removed children are SqlAlias, add notification to result if (containsSqlAlias(removedChildren)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all SqlAlias Change Notifications. * @param notifications the collection of all notifications * @return the SqlAlias Change Notifications */ private Collection getSqlAliasChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // If SqlAlias feature changed, add notification to result if (sqlAliasesChanged(notification)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all SqlStatement Change Notifications for UID SQL changes. * @param notifications the collection of all notifications * @return the SqlStatement UID Change Notifications */ private Collection getSqlSelectUIDStatementChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Determine if Select UID Sql Statements changed. if (sqlSelectUIDStatementChanged(notification)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all SqlStatement Change Notifications for User SQL changes. * @param notifications the collection of all notifications * @return the SqlStatement User Change Notifications */ private Collection getSqlSelectUserStatementChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Determine if Select User Sql Statements changed. if (sqlSelectUserStatementChanged(notification)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Notifications involving rename of a SqlTable,SqlColumn,Procedure or ProcedureParameter * @param notifications the collection of all notifications * @return the SqlTable and SqlColumn rename Notifications */ private Collection getSqlTableAndColumnRenameNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Get the object that was changed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); // If changedObject is SqlTable or SqlColumn, see if the name changed if (TransformationHelper.isSqlColumn(changedObj) || TransformationHelper.isSqlTable(changedObj) || TransformationHelper.isSqlProcedure(changedObj) || TransformationHelper.isSqlProcedureParameter(changedObj)) { // get Name feature from the changedObject Object nameFeature = ModelerCore.getModelEditor().getNameFeature((EObject)changedObj); // get feature that changed from the notification Object feature = notification.getFeature(); // If name feature changed, add notification to list if (feature != null && feature.equals(nameFeature)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Notifications involving deletion of a SqlTable,SqlColumn,SqlProcedure or SqlProcedureParameter * @param notifications the collection of all notifications * @return the SqlTable and SqlColumn remove Notifications */ private Collection getSqlTableAndColumnRemoveNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { Object removedObj = notification.getOldValue(); if (TransformationHelper.isSqlTable(removedObj) || TransformationHelper.isSqlColumn(removedObj) || TransformationHelper.isSqlProcedure(removedObj) || TransformationHelper.isSqlProcedureParameter(removedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Notifications involving SqlColumn change * @param notifications the collection of all notifications * @return the SqlColumn change Notifications */ private Collection getSqlColumnChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Get the object that was changed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); // If changedObject is SqlTable or SqlColumn, see if the name changed if (TransformationHelper.isSqlColumn(changedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Notifications involving addition of a SqlColumn * @param notifications the collection of all notifications * @return the SqlColumn add Notifications */ private Collection getSqlColumnAddNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isAdded(notification)) { // Get the added children - check whether they are SqlColumns EObject[] newChildren = NotificationUtilities.getAddedChildren(notification); for (int i = 0; i < newChildren.length; i++) { EObject child = newChildren[i]; if (TransformationHelper.isSqlColumn(child)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); break; } } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Virtual Target Table Change Notifications. * @param notifications the collection of all notifications * @return the Virtual Table Change Notifications */ private Collection getTargetVirtualTableChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Get the object that was added to Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isVirtualSqlTable(changedObj) && TransformationHelper.isValidSqlTransformationTarget(changedObj) && isCriticalFeatureChange(notification)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } private boolean isCriticalFeatureChange( Notification notification ) { if (notification.getFeature() instanceof EStructuralFeature) { EStructuralFeature esf = (EStructuralFeature)notification.getFeature(); if (esf.getFeatureID() == TransformationPackage.MAPPING_CLASS__RECURSION_LIMIT) return false; } return true; } private Notification getTableSupportsUpdateFeatureChange( Collection notifications ) { Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (TransformationHelper.isSupportsUpdateTableChangeNotification(notification)) { return notification; } } return null; } private Notification getTableMaterializedViewChange( Collection notifications ) { Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (TransformationHelper.isSetMaterializedTableChangeNotification(notification)) { return notification; } } return null; } /* * Get all Virtual Target Table Column Add Notifications. * @param notifications the collection of all notifications * @return the Virtual Table Column Add Notifications */ private Collection getTargetVirtualTableColumnAddNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isAdded(notification)) { // Get the object that was added to Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isVirtualSqlTable(changedObj) && TransformationHelper.isValidSqlTransformationTarget(changedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Virtual Target Table Column Remove Notifications. * @param notifications the collection of all notifications * @return the Virtual Table Column Remove Notifications */ private Collection getTargetVirtualTableColumnRemoveNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { // Get the object that was removed from Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isVirtualSqlTable(changedObj) && TransformationHelper.isValidSqlTransformationTarget(changedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Procedure ResultSet Column Add Notifications. (columns added to ResultSet) * @param notifications the collection of all notifications * @return the Procedure ResultSet Column Add Notifications */ private Collection getTargetProcedureResultSetColumnAddNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isAdded(notification)) { // Get the object that was added to (resultSet) Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isSqlColumnSet(changedObj)) { // parent - procedure EObject procedure = ((EObject)changedObj).eContainer(); if (TransformationHelper.isSqlVirtualProcedure(procedure) && TransformationHelper.isValidSqlTransformationTarget(procedure)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Procedure ResultSet Column Remove Notifications. (columns removed from ResultSet) * @param notifications the collection of all notifications * @return the Procedure ResultSet Column Remove Notifications */ private Collection getTargetProcedureResultSetColumnRemoveNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { // Get the object that was removed from (resultSet) Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isSqlColumnSet(changedObj)) { // parent - procedure EObject procedure = ((EObject)changedObj).eContainer(); if (TransformationHelper.isSqlVirtualProcedure(procedure) && TransformationHelper.isValidSqlTransformationTarget(procedure)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Procedure ResultSet Add Notifications. (When resultSets are added to procedures) * @param notifications the collection of all notifications * @return the Procedure ResultSet Add Notifications */ private Collection getTargetProcedureResultSetOrParamAddNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isAdded(notification) ) { // Get the object that was added to - Procedure in this case Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isSqlVirtualProcedure(changedObj) && TransformationHelper.isValidSqlTransformationTarget(changedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Procedure Parameter Change Notifications. (When Parameters are changed (i.e. datatype, name, etc)) * * @param notifications the collection of all notifications * @return the Procedure ResultSet Add Notifications */ private Collection getTargetProcedureParamChangeNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if( NotificationUtilities.isChanged(notification)) { Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if( changedObj instanceof ProcedureParameter ) { Object procedure = ((ProcedureParameter)changedObj).getProcedure(); if (TransformationHelper.isSqlVirtualProcedure(procedure) && TransformationHelper.isValidSqlTransformationTarget(procedure)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all Procedure ResultSet Remove Notifications. (When resultSets are removed from procedures) * @param notifications the collection of all notifications * @return the Procedure ResultSet Remove Notifications */ private Collection getTargetProcedureResultSetOrParamRemoveNotifications( Collection notifications ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { // Get the object that was removed from - Procedure in this case Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isSqlVirtualProcedure(changedObj) && TransformationHelper.isValidSqlTransformationTarget(changedObj)) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Get all ModelRename Notifications. * @param notifications the collection of all notifications * @return the Model Rename Notifications */ private Collection getModelRenameNotifications( Collection notifications, Object source ) { Collection result = null; Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isRemoved(notification)) { // Get the object that was changed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); // changed object - MappingRoot, and source RenameRefactorAction if (changedObj instanceof ModelAnnotation && source instanceof RenameRefactorAction) { if (result == null) { result = new ArrayList(notifications.size()); } result.add(notification); // Remove from notifications collection iter.remove(); } } } if (result == null) { result = Collections.EMPTY_LIST; } return result; } /* * Handler method for SqlTransformation add notifications. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlAliasAddNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // If any of the added children are SqlAlias, triggers update List addedAliases = getSqlAliasesAdded(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromSqlAliasNotifications(notifications); if (!addedAliases.isEmpty()) { boolean undoableAdd = NOT_UNDOABLE; if (ITransformationDiagramActionConstants.DiagramActions.UNDO_ADD_TRANSFORMATION_SOURCE) { undoableAdd = IS_UNDOABLE; } // ---------------------------------------------------------------------------------------------------------- // First transaction- // Update the SQL. // ---------------------------------------------------------------------------------------------------------- // Update the sql and reconcile the attributes in one transaction boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, undoableAdd, "Update for SqlAlias Add", this); //$NON-NLS-1$ boolean succeeded = false; try { // Do not update SQL if source is TransformationObjectEditorPage if (!(txnSource instanceof TransformationObjectEditorPage) && !(txnSource instanceof SqlEditorPanel)) { // If the SELECT is valid, may need to prompt whether to add Elements... boolean addElemsToSelect = false; if (!(txnSource instanceof ImportTransformationSqlFromTextAction)) { addElemsToSelect = shouldAddElemsToSelect(mappingRoot); } TransformationSqlHelper.updateAllSqlOnSqlAliasGroupsAdded(mappingRoot, addedAliases, addElemsToSelect, txnSource); } succeeded = true; } finally { // If we started Txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } // ---------------------------------------------------------------------------------------------------------- // Second transaction- // reconcile the targetAttributes This will add any new attributes to the target group. // ---------------------------------------------------------------------------------------------------------- requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, undoableAdd, "SqlAlias Add - reconcile target", txnSource); //$NON-NLS-1$ succeeded = false; try { // Reconcile using the updated Query TransformationMappingHelper.reconcileTargetAttributes(mappingRoot, true, txnSource); succeeded = true; } finally { // If we started Txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } // Ensure that the transformation cached status is updated after txn commit SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); /* * jh 19135: This is the code we need to execute on an AddSource operation! * (Copied from another 'handle' method in this listener class.) */ } } } /* * Handler method for SqlTransformation remove notifications. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlAliasRemoveNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get removed SqlAliases List removedAliases = getSqlAliasesRemoved(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromSqlAliasNotifications(notifications); if (!removedAliases.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update for SqlAlias Remove", this); //$NON-NLS-1$ boolean succeeded = false; try { // Do not update SQL if source is TransformationObjectEditorPage if (!(txnSource instanceof TransformationObjectEditorPage) && !(txnSource instanceof SqlEditorPanel)) { // If the SELECT is valid, may need to prompt whether to remove Elements... boolean removeElemsFromSelect = shouldRemoveGroupElemsFromSelect(mappingRoot, removedAliases); TransformationSqlHelper.updateAllSqlOnSqlAliasGroupsRemoved(mappingRoot, removedAliases, removeElemsFromSelect, txnSource); } // invalidate cached status SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); // Reconcile using the updated Query TransformationMappingHelper.reconcileTargetAttributes(mappingRoot, txnSource); succeeded = true; } finally { // If we started Txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for SqlTransformation change notifications. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlAliasChangeNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get changed SqlAliases - (removed) List removedAliases = getSqlAliasesChanged(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromSqlAliasNotifications(notifications); if (!removedAliases.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update for SqlAlias Change", this); //$NON-NLS-1$ boolean succeeded = false; try { // Do not update SQL if source is TransformationObjectEditorPage if (!(txnSource instanceof TransformationObjectEditorPage) && !(txnSource instanceof SqlEditorPanel)) { // If the SELECT is valid, may need to prompt whether to remove Elements... boolean removeElemsFromSelect = shouldRemoveGroupElemsFromSelect(mappingRoot, removedAliases); TransformationSqlHelper.updateAllSqlOnSqlAliasGroupsRemoved(mappingRoot, removedAliases, removeElemsFromSelect, txnSource); } // Reconcile using the updated Query TransformationMappingHelper.reconcileTargetAttributes(mappingRoot, txnSource); succeeded = true; } finally { // If we started Txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Sql statement change notifications. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlUIDStatementChangeNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Determine if this Notification is coming from the SqlTransformationHelper boolean sourceIsSqlHelper = isSqlHelperSource(txnSource); // Source is NOT SQLTransformationHelper and NOT TransformationObjectEditorPage, reconcile if (!sourceIsSqlHelper && !(txnSource instanceof TransformationObjectEditorPage)) { // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromSqlUIDStatementNotifications(notifications); // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update for Sql Statment Change", this); //$NON-NLS-1$ boolean succeeded = false; try { // Reconcile the mapping root Inputs / Attributes / etc to conform to the SQL TransformationMappingHelper.reconcileMappingsOnSqlChange(mappingRoot, txnSource); succeeded = true; } finally { // If we started Txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Sql Table and Column rename notifications. This method will invalidate the * SqlMappingRootCache. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlTableAndColumnRenameNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Gather up all the groups that have renames Set groups = new HashSet(); Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // Get the object that was changed - renamed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); // changedObject is SqlTable if (TransformationHelper.isSqlTable(changedObj)) { groups.add(changedObj); // changedObject is SqlColumn } else if (TransformationHelper.isSqlColumn(changedObj)) { // parent of column is the source group EObject sourceGrp = ((EObject)changedObj).eContainer(); groups.add(sourceGrp); } else if (TransformationHelper.isSqlProcedure(changedObj)) { groups.add(changedObj); } else if (TransformationHelper.isSqlProcedureParameter(changedObj)) { // parent of parameter is the source procedure EObject sourceProc = ((EObject)changedObj).eContainer(); groups.add(sourceProc); } } if (!groups.isEmpty()) { TransformationHelper.invalidateCachedRootsWithSourceGroups(groups); TransformationHelper.invalidateCachedRootsWithTargetGroups(groups); } } } /* * Handler method for SqlTable and SqlColumn remove notifications. This method will invalidate the * SqlMappingRootCache. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlTableAndColumnRemoveNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Gather up all the groups that have renames Set groups = new HashSet(); Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // Get the object that was removed Object removedObj = notification.getOldValue(); // removed Object is SqlTable if (TransformationHelper.isSqlTable(removedObj)) { groups.add(removedObj); // removed Object is SqlColumn } else if (TransformationHelper.isSqlColumn(removedObj)) { // parent of column is the sourceGroup Object sourceGrp = ModelerCore.getModelEditor().getChangedObject(notification); groups.add(sourceGrp); } else if (TransformationHelper.isSqlProcedure(removedObj)) { groups.add(removedObj); } else if (TransformationHelper.isSqlProcedureParameter(removedObj)) { // parent of parameter is the source procedure Object sourceProc = ModelerCore.getModelEditor().getChangedObject(notification); groups.add(sourceProc); } } if (!groups.isEmpty()) { TransformationHelper.invalidateCachedRootsWithSourceGroups(groups); } } } /* * Handler method for Sql Column change notifications. This method will invalidate the * SqlMappingRootCache - the column type or other important feature may have changed. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlColumnChangeNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Gather up all the groups that have renames Set groups = new HashSet(); Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // Get the object that was changed - renamed Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (TransformationHelper.isSqlColumn(changedObj)) { // parent of column is the group EObject grp = ((EObject)changedObj).eContainer(); groups.add(grp); } } if (!groups.isEmpty()) { TransformationHelper.invalidateCachedRootsWithSourceGroups(groups); TransformationHelper.invalidateCachedRootsWithTargetGroups(groups); } } } /* * Handler method for Table Column Add notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleSqlTableColumnAddNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get Tables Added To Set tables = getSqlTablesAddedTo(notifications); if (!tables.isEmpty()) { SqlMappingRootCache.invalidateRootsWithSourceGroups(tables); } } } /* * Handler method for Virtual Table Change notifications. Sole purpose of this method is * to invalidate the mappingRoot cache to cover case where allows update has changed. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetVirtualTableChangeNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromVTableNotifications(notifications); // Handle changes to table 'supportsUpdate' state // Assumption is that it is always safe to change columns to not updateable, if the table 'supportsUpdate' // is set to false. This is default behavior, handled in TableImpl. Notification notif = getTableSupportsUpdateFeatureChange(notifications); if (notif != null) { // Handle the case where 'supportsUpdate' is set to true. boolean isSupportsUpdate = notif.getNewBooleanValue(); if (isSupportsUpdate) { // If the ignore flag hasnt been set, show the dialog if (!ignoreTableSupportsUpdateChangedTrue) { final String dialogTitle = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChanged.title"); //$NON-NLS-1$ final String disableFutureMessage = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChangedTrue.disableFutureDialogMessage"); //$NON-NLS-1$ final String message = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChangedTrue.message"); //$NON-NLS-1$ // Prompt whether to add the Group Elements to the query // put on SWT thread UiUtil.runInSwtThread(new Runnable() { @Override public void run() { // Ensure that preference is false initially, this may be reset UiPlugin.getDefault().getPreferenceStore().setValue(PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_TRUE, ""); //$NON-NLS-1$ // show the info dialog MessageDialogWithToggle dialog = MessageDialogWithToggle.openYesNoQuestion(UiUtil.getWorkbenchWindow().getShell(), dialogTitle, message, disableFutureMessage, false, UiPlugin.getDefault().getPreferenceStore(), PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_TRUE); int retCode = dialog.getReturnCode(); if (retCode == IDialogConstants.YES_ID) { setColumnsUpdateableOnTableUpdateable = true; } else { setColumnsUpdateableOnTableUpdateable = false; } } }, true); String ignoreChangesStr = UiPlugin.getDefault().getPreferenceStore().getString(PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_TRUE); if (MessageDialogWithToggle.ALWAYS.equals(ignoreChangesStr)) { ignoreTableSupportsUpdateChangedTrue = true; } } if (setColumnsUpdateableOnTableUpdateable) { Object table = notif.getNotifier(); TransformationHelper.setTableColumnsSupportsUpdate(table, true); } // Handle the case where 'supportsUpdate' is set to false } else { // If the ignore flag hasnt been set, show the dialog if (!ignoreTableSupportsUpdateChangedFalse) { final String dialogTitle = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChanged.title"); //$NON-NLS-1$ final String disableFutureMessage = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChangedFalse.disableFutureDialogMessage"); //$NON-NLS-1$ final String message = UiConstants.Util.getString("TransformationNotificationListener.tableSupportsUpdateChangedFalse.message"); //$NON-NLS-1$ // Show Table supports update dialog UiUtil.runInSwtThread(new Runnable() { @Override public void run() { // Ensure that preference is false initially, this may be reset UiPlugin.getDefault().getPreferenceStore().setValue(PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_FALSE, ""); //$NON-NLS-1$ // show the info dialog MessageDialogWithToggle.openInformation(UiUtil.getWorkbenchWindow().getShell(), dialogTitle, message, disableFutureMessage, false, UiPlugin.getDefault().getPreferenceStore(), PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_FALSE); } }, true); String ignoreChangesStr = UiPlugin.getDefault().getPreferenceStore().getString(PluginConstants.Prefs.TableSupportsUpdateChange.IGNORE_TABLE_SUPPORTSUPDATE_CHANGED_FALSE); if (MessageDialogWithToggle.ALWAYS.equals(ignoreChangesStr)) { ignoreTableSupportsUpdateChangedFalse = true; } } } } notif = getTableMaterializedViewChange(notifications); if( notif != null ) { boolean isMaterialized = notif.getNewBooleanValue(); if( !isMaterialized ) { // Need to remove the reference Object table = notif.getNotifier(); if( TransformationHelper.isVirtualSqlTable(table) ) { ((Table)table).setMaterializedTable(null); } } } SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); } } /* * Handler method for Virtual Table Column Add notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetVirtualTableColumnAddNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get added Columns List addedColumns = getSqlColumnsAdded(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromVTableNotifications(notifications); if (!addedColumns.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Create atttr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { Iterator iter = addedColumns.iterator(); boolean colsAdded = false; while (iter.hasNext()) { Object column = iter.next(); // Add Attribute Mapping for the new Attributes if (TransformationHelper.isSqlColumn(column)) { AttributeMappingHelper.createAttributeMapping(mappingRoot, (EObject)column, txnSource); colsAdded = true; } } if (colsAdded) { SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); } succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Virtual Table Column Remove notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetVirtualTableColumnRemoveNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get removed target Elements List removedColumns = getSqlColumnsRemoved(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromVTableNotifications(notifications); if (!removedColumns.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Remove atttr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { // for defect 15131 -- do not overwrite dirty Teditor changes without a prompt boolean overwriteDirty = false; // Do not update SQL if source is TransformationObjectEditorPage if (!(txnSource instanceof TransformationObjectEditorPage)) { // First, discover if editor is dirty: TransformationObjectEditorPage transOEP = null; boolean isDirty = false; // is editor open? ModelResource mdlRsrc = ModelUtilities.getModelResourceForModelObject(mappingRoot); IResource resource = mdlRsrc.getResource(); ModelEditor medit = ModelEditorManager.getModelEditorForFile((IFile)resource, false); if (medit != null) { // Yes, check to see if dirty: ModelObjectEditorPage moep = medit.getActiveObjectEditor(); if (moep != null && moep instanceof TransformationObjectEditorPage) { transOEP = (TransformationObjectEditorPage)moep; if (transOEP.hasPendingChanges()) { // yes, pending T-Editor changes: isDirty = true; } // endif -- has pending } // endif -- instance of TEditor } // endif -- editor is open for object if (isDirty) { // yes, editor is dirty. // build message: final String message = UiConstants.Util.getString("TransformationNotificationListener.saveBeforeChangesMsg", //$NON-NLS-1$ resource.getName()); // build buttons, and bad notes, if any: final String[] radioButtons = {SBC_RADIO_SAVE, SBC_RADIO_IGNORE, SBC_RADIO_HALT}; final IStatus[] radioErrors = {null, null, null}; // is saved valid? boolean savedValid = TransformationHelper.isValid(mappingRoot, QueryValidator.SELECT_TRNS); if (!savedValid) { // add a warning: radioErrors[1] = new Status(IStatus.WARNING, TransformationPlugin.PLUGIN_ID, -1, SBC_NOTE, null); } // endif // is dirty valid? String dirtysql = transOEP.getCurrentSqlEditor().getText(); // the Teditor page should be loaded in // transOEP already QueryValidator qv = new TransformationValidator((SqlTransformationMappingRoot)mappingRoot, false); QueryValidationResult qvr = qv.validateSql(dirtysql, QueryValidator.SELECT_TRNS, false); boolean dirtyValid = qvr.isParsable(); if (!dirtyValid) { // add a warning: radioErrors[0] = new Status(IStatus.WARNING, TransformationPlugin.PLUGIN_ID, -1, SBC_NOTE, null); } // endif // Note that the first radio in the array (save) is selected by default. // put on SWT thread UiUtil.runInSwtThread(new Runnable() { @Override public void run() { uiIntegerResult = RadioMessageDialog.openMulti(UiUtil.getWorkbenchWindow().getShell(), MessageDialog.WARNING, SAVE_BEFORE_CHANGE_TITLE, message, SBC_GROUP_TITLE, radioButtons, radioErrors, 0); // 0=default radio=save } }, true); int result = uiIntegerResult; switch (result) { case 0: // save: { // selected save chgs first: TransformationHelper.setSelectSqlString(mappingRoot, dirtysql, NOT_SIGNIFICANT, txnSource); TransformationSqlHelper.updateAllSqlOnElementsRemoved(mappingRoot, removedColumns, txnSource); overwriteDirty = true; } break; case 1: // ignore: { // ignore changes, so overwrite: TransformationSqlHelper.updateAllSqlOnElementsRemoved(mappingRoot, removedColumns, txnSource); overwriteDirty = true; } break; case 2: // halt: { // don't save changes, don't overwrite, don't do anything: overwriteDirty = false; } break; default: break; } // endswitch } else { // no, not open or not dirty, proceed as normal (ie, how it used to work): // If the SELECT is valid, may need to prompt whether to remove Elements... if (!(txnSource instanceof ReconcileTransformationAction) && shouldRemoveElemsFromSelect(mappingRoot, removedColumns)) { TransformationSqlHelper.updateAllSqlOnElementsRemoved(mappingRoot, removedColumns, txnSource); overwriteDirty = true; // user asked for it } // endif -- shouldRemove } // endif -- isDirty } Iterator iter = removedColumns.iterator(); boolean mappingRemoved = false; while (iter.hasNext()) { Object column = iter.next(); // Remove Attribute Mappings for the removed Attributes if (TransformationHelper.isSqlColumn(column)) { AttributeMappingHelper.removeAttributeMapping(mappingRoot, (EObject)column, txnSource); mappingRemoved = true; } } if (mappingRemoved) { SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource, overwriteDirty); } succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Procedure ResultSet Column Add notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetProcedureResultSetColumnAddNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get added Columns List addedColumns = getSqlColumnsAdded(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromProcResultSetColumnNotifications(notifications); if (!addedColumns.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Add atttr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { Iterator iter = addedColumns.iterator(); while (iter.hasNext()) { Object column = iter.next(); // Add Attribute Mapping for the new Attributes if (TransformationHelper.isSqlColumn(column)) { AttributeMappingHelper.createAttributeMapping(mappingRoot, (EObject)column, txnSource); } } succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Procedure ResultSet Column Remove notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetProcedureResultSetColumnRemoveNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get removed Columns List removedColumns = getSqlColumnsRemoved(notifications); // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromProcResultSetColumnNotifications(notifications); if (!removedColumns.isEmpty()) { // Start txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Remove atttr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { Iterator iter = removedColumns.iterator(); while (iter.hasNext()) { Object column = iter.next(); // Remove Attribute Mappings for the removed Attributes if (TransformationHelper.isSqlColumn(column)) { AttributeMappingHelper.removeAttributeMapping(mappingRoot, (EObject)column, txnSource); } } succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } } /* * Handler method for Procedure ResultSet or Parameter Add notifications. The added objects * may either be a resultSet or ProcedureParameter. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetProcedureResultSetOrParamAddNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromProcResultSetOrParamNotifications(notifications); // start txn if not already in txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update attr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { // Invalidate cached Status regardless of resultSet or parameter addition SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); // Update attribute mappings AttributeMappingHelper.updateAttributeMappings(mappingRoot, txnSource); succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } /* * Handler method for Procedure Parameter Change notifications. * * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetProcedureParamChangeNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromProcParamNotifications(notifications); // start txn if not already in txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update attr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { // Invalidate cached Status regardless of resultSet or parameter addition SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); // Update attribute mappings AttributeMappingHelper.updateAttributeMappings(mappingRoot, txnSource); succeeded = true; } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } /* * Handler method for Procedure ResultSet or Parameter Remove notifications. The removed objects * may either be a resultSet or ProcedureParameter. * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleTargetProcedureResultSetOrParamRemoveNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Get mapping root for the SqlTransformation EObject mappingRoot = getMappingRootFromProcResultSetOrParamNotifications(notifications); // start txn if not already in txn boolean requiredStart = ModelerCore.startTxn(NOT_SIGNIFICANT, IS_UNDOABLE, "Update attr mappings", this); //$NON-NLS-1$ boolean succeeded = false; try { // Invalidate cached Status regardless of resultSet or parameter removal SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); // Get Target attributes List targetAttrs = TransformationHelper.getTransformationTargetAttributes(mappingRoot); if (targetAttrs != null && !targetAttrs.isEmpty()) { SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); AttributeMappingHelper.updateAttributeMappings(mappingRoot, txnSource); succeeded = true; } } finally { // If we start txn, commit it if (requiredStart) { if (succeeded) { ModelerCore.commitTxn(); } else { ModelerCore.rollbackTxn(); } } } } } /* * Handler method for ModelRename notifications * @param notifications the collection of notifications * @param txnSource the source for the transaction */ private void handleModelRenameNotifications( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { Iterator iter = notifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); if (NotificationUtilities.isChanged(notification)) { // Get all Transformation Roots for the resource and clean out the cache for ALL of them Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); ModelResource modelResource = ModelUtilities.getModelResource(changedObj); if( modelResource != null ) { try { // Process all transformations in the TransformationContainer final EmfResource emfRes = (EmfResource)modelResource.getEmfResource(); final List transformations = emfRes.getModelContents().getTransformations(); for (Iterator i = transformations.iterator(); i.hasNext();) { EObject eObj = (EObject)i.next(); if (eObj instanceof SqlTransformationMappingRoot) { SqlTransformationMappingRoot mappingRoot = (SqlTransformationMappingRoot)eObj; SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); SqlMappingRootCache.invalidateInsertStatus(mappingRoot, true, txnSource); SqlMappingRootCache.invalidateUpdateStatus(mappingRoot, true, txnSource); SqlMappingRootCache.invalidateDeleteStatus(mappingRoot, true, txnSource); } } } catch (ModelWorkspaceException e) { Util.log(IStatus.ERROR, e, e.getMessage()); } } } } } } /* * Handler method for Undo notifications. Basically, the undo/redo notifications are ignored unless * the SQL statement has changed. In the event that the SQL is being changed, then the only thing that * needs to be done is to invalidate the SqlMappingRootCache. This insures that the cache will not be * stale. * @param notifications the collection of notifications */ private void handleUndo( Collection notifications, Object txnSource ) { if (!notifications.isEmpty()) { // Check for SQL Modifications - if SQL mods, then cache needs to be invalidated Collection selectUserNotifications = getSqlSelectUserStatementChangeNotifications(notifications); Collection selectUIDNotifications = getSqlSelectUIDStatementChangeNotifications(notifications); // If UID SQL changed, invalidate cache status if (!selectUIDNotifications.isEmpty()) { EObject mappingRoot = getMappingRootFromSqlUIDStatementNotifications(selectUIDNotifications); SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); // else, If User SQL changed, invalidate cache status } else if (!selectUserNotifications.isEmpty()) { EObject mappingRoot = getMappingRootFromSqlUserStatementNotifications(selectUserNotifications); SqlMappingRootCache.invalidateSelectStatus(mappingRoot, true, txnSource); } } // --------------------------------------------------------- // Function Model Scalar Function or parameter changes // --------------------------------------------------------- functionHandler.handleNotifications(notifications, txnSource); } /* * Get MappingRoot from SqlAlias Notifications * @param sqlAliasNotifications the SqlAlias Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromSqlAliasNotifications( Collection sqlAliasNotifications ) { EObject mappingRoot = null; Iterator iter = sqlAliasNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(firstNotification); // Mapping root for the SqlTransformation mappingRoot = TransformationHelper.getMappingRoot((MappingHelper)changedObj); } return mappingRoot; } /* * Get MappingRoot from VirtualTable Notifications * @param vTableNotifications the VirtualTable Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromVTableNotifications( Collection vTableNotifications ) { EObject mappingRoot = null; Iterator iter = vTableNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the Transformation target Object changedObj = ModelerCore.getModelEditor().getChangedObject(firstNotification); // Mapping root for the SqlTransformation mappingRoot = TransformationHelper.getTransformationMappingRoot((EObject)changedObj); } return mappingRoot; } /* * Get MappingRoot from Procedure ResultSet Notifications * @param resultSetNotifications the Procedure ResultSet Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromProcResultSetColumnNotifications( Collection resultSetNotifications ) { EObject mappingRoot = null; Iterator iter = resultSetNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the ResultSet Object resultSet = ModelerCore.getModelEditor().getChangedObject(firstNotification); if (TransformationHelper.isSqlColumnSet(resultSet)) { // The parent of the ResultSet is the Procedure EObject procedure = ((EObject)resultSet).eContainer(); // Mapping root for the SqlTransformation mappingRoot = TransformationHelper.getTransformationMappingRoot(procedure); } } return mappingRoot; } /* * Get MappingRoot from Procedure ResultSet Notifications * @param resultSetNotifications the Procedure ResultSet or Parameter Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromProcResultSetOrParamNotifications( Collection resultSetNotifications ) { EObject mappingRoot = null; Iterator iter = resultSetNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the Procedure Object procedure = ModelerCore.getModelEditor().getChangedObject(firstNotification); if (TransformationHelper.isSqlProcedure(procedure)) { // Mapping root for the SqlTransformation mappingRoot = TransformationHelper.getTransformationMappingRoot((EObject)procedure); } } return mappingRoot; } /* * Get MappingRoot from Procedure Parameter Notifications * @param parameterNotifications the Procedure Parameter Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromProcParamNotifications( Collection parameterNotifications ) { EObject mappingRoot = null; Iterator iter = parameterNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the Procedure Object parameter = ModelerCore.getModelEditor().getChangedObject(firstNotification); if (TransformationHelper.isSqlProcedureParameter(parameter)) { // Mapping root for the SqlTransformation mappingRoot = TransformationHelper.getTransformationMappingRoot((EObject)((ProcedureParameter)parameter).getProcedure()); } } return mappingRoot; } /* * Get MappingRoot from UID SqlStatement change Notifications * @param notification the collection of UID SqlStatement Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromSqlUIDStatementNotifications( Collection sqlNotifications ) { EObject mappingRoot = null; Iterator iter = sqlNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(firstNotification); // Mapping root for the UID SqlTransformation. mappingRoot = TransformationHelper.getMappingRoot((MappingHelper)changedObj); } return mappingRoot; } /* * Get MappingRoot from UID SqlStatement change Notifications * @param notification the collection of UID SqlStatement Notifications * @return the mappingRoot EObject */ private EObject getMappingRootFromSqlUserStatementNotifications( Collection sqlNotifications ) { EObject mappingRoot = null; Iterator iter = sqlNotifications.iterator(); Notification firstNotification = (Notification)iter.next(); if (firstNotification != null) { // The changed Object is the SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(firstNotification); // The parent is the UID SqlTransformation - it has the correct MappingRoot EObject parentEObj = ((EObject)changedObj).eContainer(); // Mapping root for the UID SqlTransformation. mappingRoot = TransformationHelper.getMappingRoot((MappingHelper)parentEObj); } return mappingRoot; } /* * Get SqlAliases added, given a Collection of Add Notifications * @param addNotifications the add Notifications * @return the List of SqlAlias objects */ private List getSqlAliasesAdded( Collection addNotifications ) { List sqlAliasList = new ArrayList(); Iterator iter = addNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); EObject[] newChildren = NotificationUtilities.getAddedChildren(notification); for (int i = 0; i < newChildren.length; i++) { if (newChildren[i] instanceof SqlAlias && !sqlAliasList.contains(newChildren[i])) { sqlAliasList.add(newChildren[i]); } } } return sqlAliasList; } /* * Get SqlAliases removed, given a Collection of Remove Notifications * @param removeNotifications the remove Notifications * @return the List of SqlAlias objects */ private List getSqlAliasesRemoved( Collection removeNotifications ) { List sqlAliasList = new ArrayList(); Iterator iter = removeNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); EObject[] newChildren = NotificationUtilities.getRemovedChildren(notification); for (int i = 0; i < newChildren.length; i++) { if (newChildren[i] instanceof SqlAlias && !sqlAliasList.contains(newChildren[i])) { sqlAliasList.add(newChildren[i]); } } } return sqlAliasList; } /* * Get SqlAliases changed, given a Collection of Change Notifications * @param changeNotifications the change Notifications * @return the List of SqlAlias objects */ private List getSqlAliasesChanged( Collection changeNotifications ) { List sqlAliasList = new ArrayList(); Iterator iter = changeNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // The old Value represents the SqlAlias or Aliases that were removed Object removedAlias = notification.getOldValue(); if (removedAlias instanceof SqlAlias && !sqlAliasList.contains(removedAlias)) { sqlAliasList.add(removedAlias); } else if (removedAlias instanceof List) { Iterator listIter = ((List)removedAlias).iterator(); while (listIter.hasNext()) { Object nextObj = listIter.next(); if (nextObj instanceof SqlAlias && !sqlAliasList.contains(nextObj)) { sqlAliasList.add(nextObj); } } } } return sqlAliasList; } /* * Get SqlColumns added, given a Collection of Add Notifications * @param addNotifications the add Notifications * @return the List of SqlColumns */ private List getSqlColumnsAdded( Collection addNotifications ) { List tableColumnList = new ArrayList(); Iterator iter = addNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); EObject[] newChildren = NotificationUtilities.getAddedChildren(notification); for (int i = 0; i < newChildren.length; i++) { if (TransformationHelper.isSqlColumn(newChildren[i]) && !tableColumnList.contains(newChildren[i])) { tableColumnList.add(newChildren[i]); } } } return tableColumnList; } /* * Get SqlColumns removed, given a Collection of Remove Notifications * @param removeNotifications the remove Notifications * @return the List of SqlColumns */ private List getSqlColumnsRemoved( Collection removeNotifications ) { List tableColumnList = new ArrayList(); Iterator iter = removeNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); EObject[] removedChildren = NotificationUtilities.getRemovedChildren(notification); for (int i = 0; i < removedChildren.length; i++) { if (TransformationHelper.isSqlColumn(removedChildren[i]) && !tableColumnList.contains(removedChildren[i])) { tableColumnList.add(removedChildren[i]); } } } return tableColumnList; } /* * Get SqlTables added, given a Collection of Column Add Notifications * @param addNotifications the add Notifications * @return the List of SqlTables */ private Set getSqlTablesAddedTo( Collection addNotifications ) { Set tableSet = new HashSet(); Iterator iter = addNotifications.iterator(); while (iter.hasNext()) { Notification notification = (Notification)iter.next(); // Get the object that changed - table Object table = ModelerCore.getModelEditor().getChangedObject(notification); tableSet.add(table); } return tableSet; } /* * Check whether any of the supplied EObjects are SqlAliases * @param eObjects the array of EObjects * @return 'true' if any are SqlAliases, 'false' if not */ private boolean containsSqlAlias( EObject[] eObjects ) { boolean hasSqlAlias = false; for (int i = 0; i < eObjects.length; i++) { if (eObjects[i] instanceof SqlAlias) { if( !functionHandler.shouldHandleChangedObject( ((SqlAlias)eObjects[i]).getAliasedObject()) ) { hasSqlAlias = true; break; } } } return hasSqlAlias; } /* * Method to determine whether the Notification source is the TransformationSqlHelper * @param source the source to test * @return 'true' if the source is the SqlTransformationHelper, 'false' if not. */ private boolean isSqlHelperSource( Object source ) { boolean isSqlHelper = false; if (source != null && source.equals(TransformationSqlHelper.getInstance())) { isSqlHelper = true; } return isSqlHelper; } /* * Method to determine whether the notification is for change of the SqlAliases. * @param notification the notification * @return 'true' if the feature changed is SqlAliases, 'false' if not. */ private boolean sqlAliasesChanged( Notification notification ) { boolean aliasesChanged = false; // Make sure that the changed Object is SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (changedObj instanceof SqlTransformation) { // See if the changed feature is the aliases int changedFeature = notification.getFeatureID(SqlTransformation.class); boolean isFunction = false; if( notification.getOldValue() instanceof SqlAlias ) { SqlAlias alias = (SqlAlias)notification.getOldValue(); if( alias.getAliasedObject() instanceof ScalarFunction ) { isFunction = true; } } if (!isFunction && changedFeature == TransformationPackage.SQL_TRANSFORMATION__ALIASES) { aliasesChanged = true; } } return aliasesChanged; } /* * Method to determine whether the notification is for a change of one of the SELECT * UID SQL statements. * @param notification the notification * @return 'true' if the feature changed is one of the UID SQL Statements, 'false' if not. */ private boolean sqlSelectUIDStatementChanged( Notification notification ) { boolean selectUIDStatementChanged = false; int changedFeature = notification.getFeatureID(SqlTransformation.class); // Changed Feature is Sql SELECT if (changedFeature == TransformationPackage.SQL_TRANSFORMATION__SELECT_SQL) { // Get the object that changed - SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (changedObj != null && changedObj instanceof SqlTransformation) { // Get the Parent of the changed Object (SqlTransformation) EObject parent = ((EObject)changedObj).eContainer(); // Only consider notification if the parent is NOT a SqlTransformation // Ignore SqlTransformation that has SqlTransformation parent (UserTransformation -string version) if (!TransformationHelper.isSqlTransformation(parent)) { selectUIDStatementChanged = true; } } } return selectUIDStatementChanged; } /* * Method to determine whether the notification is for a change of one of the SELECT * User SQL statements. * @param notification the notification * @return 'true' if the feature changed is one of the User SQL Statements, 'false' if not. */ private boolean sqlSelectUserStatementChanged( Notification notification ) { boolean selectUserStatementChanged = false; int changedFeature = notification.getFeatureID(SqlTransformation.class); // Changed Feature is Sql SELECT if (changedFeature == TransformationPackage.SQL_TRANSFORMATION__SELECT_SQL) { // Get the object that changed - SqlTransformation Object changedObj = ModelerCore.getModelEditor().getChangedObject(notification); if (changedObj != null && changedObj instanceof SqlTransformation) { // Get the Parent of the changed Object (SqlTransformation) EObject parent = ((EObject)changedObj).eContainer(); // The User SqlTransformation has a SqlTransformation parent if (TransformationHelper.isSqlTransformation(parent)) { selectUserStatementChanged = true; } } } return selectUserStatementChanged; } /* * Method to determine whether group elements should be added to the select. The user will * be prompted if the transformation SELECT query is a Valid query other than a SELECT *. For * a valid SELECT * query, it is assumed that the Group Elements are to be added. * @param mappingRoot the transformation MappingRoot * @return 'true' if elems should be added for added groups, 'false' if not. */ private boolean shouldAddElemsToSelect( Object mappingRoot ) { // If the SELECT is valid, may need to prompt whether to add Elements... boolean addElemsToSelect = false; if (TransformationHelper.isValid(mappingRoot, QueryValidator.SELECT_TRNS)) { ICommand selectCommand = SqlMappingRootCache.getSelectCommand(mappingRoot); if (selectCommand instanceof IQuery) { // Check if callbacks are disabled IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); boolean disableCallbacks = prefStore.getBoolean(PluginConstants.Prefs.Callbacks.DISABLE_CALLBACKS); ISelect querySelect = ((IQuery)selectCommand).getSelect(); // Query is Valid, but not "SELECT *" - ask the user if (!TransformationSqlHelper.isSelectStar(querySelect) && !disableCallbacks) { final String message = UiConstants.Util.getString("TransformationNotificationListener.addSQLElemGrpAttrsMsg", //$NON-NLS-1$ DEFAULT_ADDED_SOURCE); // Prompt whether to add the Group Elements to the query // put on SWT thread UiUtil.runInSwtThread(new Runnable() { @Override public void run() { uiBooleanResult = MessageDialog.openQuestion(UiUtil.getWorkbenchWindow().getShell(), ADD_SQL_ELEM_GRP_REFS_TITLE, message); } }, true); addElemsToSelect = uiBooleanResult; // Query is Valid "SELECT *", elements should be added } else { addElemsToSelect = true; } } } return addElemsToSelect; } /* * Method to determine whether group elements should be removed from the select. The user will * be prompted if the transformation SELECT query is a Valid query other than a SELECT *. For * a valid SELECT * query, it is assumed that the Group Elements are to be removed. * @param mappingRoot the transformation MappingRoot * @param sqlAliasGroups the SqlAlias groups being removed * @return 'true' if elems should be added for added groups, 'false' if not. */ private boolean shouldRemoveGroupElemsFromSelect( Object mappingRoot, List sqlAliasGroups ) { // If the SELECT is valid, may need to prompt whether to remove Elements... boolean removeElemsFromSelect = false; if (TransformationHelper.isValid(mappingRoot, QueryValidator.SELECT_TRNS)) { ICommand selectCommand = SqlMappingRootCache.getSelectCommand(mappingRoot); if (selectCommand instanceof IQuery) { // Check if callbacks are disabled IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); boolean disableCallbacks = prefStore.getBoolean(PluginConstants.Prefs.Callbacks.DISABLE_CALLBACKS); ISelect querySelect = ((IQuery)selectCommand).getSelect(); // Query is Valid, but not "SELECT *" - ask the user if (!TransformationSqlHelper.isSelectStar(querySelect) && TransformationSqlHelper.hasSqlAliasGroupAttributes((IQuery)selectCommand, sqlAliasGroups) && !disableCallbacks) { final String message = UiConstants.Util.getString("TransformationNotificationListener.removeSQLElemGrpRefsMsg", //$NON-NLS-1$ DEFAULT_REMOVED_SOURCE); // Prompt whether to remove the Group Elements from the query // put on SWT thread UiUtil.runInSwtThread(new Runnable() { @Override public void run() { uiBooleanResult = MessageDialog.openQuestion(UiUtil.getWorkbenchWindow().getShell(), REMOVE_SQL_ELEM_GRP_REFS_TITLE, message); } }, true); removeElemsFromSelect = uiBooleanResult; // Query is Valid "SELECT *", elements should be removed } else { removeElemsFromSelect = true; } } } return removeElemsFromSelect; } /* * Method to determine whether elements should be removed from the select. The user will * be prompted if the transformation SELECT query is a Valid query other than a SELECT *. For * a valid SELECT * query, it is assumed that the Group Elements are to be removed. * @param mappingRoot the transformation MappingRoot * @param sqlColumns the SQL columns being removed * @return 'true' if elems should be removed, 'false' if not. */ private boolean shouldRemoveElemsFromSelect( Object mappingRoot, List sqlColumns ) { // If the SELECT is valid, may need to prompt whether to remove Elements... boolean removeElemsFromSelect = false; if (TransformationHelper.isValid(mappingRoot, QueryValidator.SELECT_TRNS)) { ICommand selectCommand = SqlMappingRootCache.getSelectCommand(mappingRoot); IQuery selectQuery = null; if (selectCommand instanceof IQueryCommand) { selectQuery = ((IQueryCommand)selectCommand).getProjectedQuery(); } if (selectQuery != null) { // Check if callbacks are disabled IPreferenceStore prefStore = UiPlugin.getDefault().getPreferenceStore(); boolean disableCallbacks = prefStore.getBoolean(PluginConstants.Prefs.Callbacks.DISABLE_CALLBACKS); // Query has the projecte SQL symbols if (TransformationSqlHelper.hasSqlElemSymbols(selectQuery, sqlColumns) && !disableCallbacks) { // Prompt whether to remove the Elements from the query // put on SWT thread UiUtil.runInSwtThread(new Runnable() { @Override public void run() { uiBooleanResult = MessageDialog.openQuestion(UiUtil.getWorkbenchWindow().getShell(), REMOVE_SQL_ELEMS_TITLE, REMOVE_SQL_ELEMS_MSG); } }, true); removeElemsFromSelect = uiBooleanResult; // Query is Valid "SELECT *", elements should be removed } else { removeElemsFromSelect = true; } } } return removeElemsFromSelect; } /** * @see org.teiid.core.designer.event.EventObjectListener#processEvent(java.util.EventObject) * @since 4.2 */ @Override public void processEvent( EventObject obj ) { ModelResourceEvent event = (ModelResourceEvent)obj; if (event.getType() == ModelResourceEvent.RELOADED) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SqlMappingRootCache.invalidateRootsOnProjectOrModelRemove(); } }); } functionHandler.processModelResourceEvent(event); } private class WorkspaceNotificationListener implements ModelWorkspaceNotificationListener { public WorkspaceNotificationListener() { } @Override public void notifyAdd( ModelWorkspaceNotification notification ) { } @Override public void notifyRemove( ModelWorkspaceNotification notification ) { // Invalidate the SqlMappingRoot cache on Project or Model Removal if (notification.isPostChange()) { // Project Close/Remove notification if (notification.isProject()) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SqlMappingRootCache.invalidateRootsOnProjectOrModelRemove(); } }); // Model Remove notification } else if (notification.isFile()) { IResource resource = (IResource)notification.getNotifier(); if (ModelUtil.isModelFile(resource)) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SqlMappingRootCache.invalidateRootsOnProjectOrModelRemove(); } }); } } } } @Override public void notifyMove( ModelWorkspaceNotification notification ) { } @Override public void notifyRename( ModelWorkspaceNotification notification ) { } @Override public void notifyOpen( ModelWorkspaceNotification notification ) { } @Override public void notifyClosing( ModelWorkspaceNotification notification ) { } @Override public void notifyChanged( Notification theNotification ) { } @Override public void notifyReloaded( ModelWorkspaceNotification notification ) { } @Override public void notifyClean( final IProject proj ) { Display.getDefault().asyncExec(new Runnable() { @Override public void run() { SqlMappingRootCache.invalidateCacheForProject(proj); } }); } } }