package org.teiid.designer.transformation.ui.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.mapping.MappingHelper;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.handlers.HandlerUtil;
import org.teiid.designer.core.ModelerCore;
import org.teiid.designer.core.metamodel.aspect.sql.SqlAspect;
import org.teiid.designer.core.metamodel.aspect.sql.SqlTableAspect;
import org.teiid.designer.core.query.QueryValidationResult;
import org.teiid.designer.core.query.QueryValidator;
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.metamodels.transformation.SqlTransformation;
import org.teiid.designer.metamodels.transformation.SqlTransformationMappingRoot;
import org.teiid.designer.transformation.ui.UiConstants;
import org.teiid.designer.transformation.ui.UiPlugin;
import org.teiid.designer.transformation.ui.editors.TransformationObjectEditorPage;
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.validation.TransformationValidator;
import org.teiid.designer.ui.common.widget.ListMessageDialog;
import org.teiid.designer.ui.editors.ModelEditorManager;
import org.teiid.designer.ui.editors.ModelObjectEditorPage;
import org.teiid.designer.ui.editors.MultiPageModelEditor;
import org.teiid.designer.ui.viewsupport.ModelObjectUtilities;
import org.teiid.designer.ui.viewsupport.ModelUtilities;
/**
* @since 8.0
*/
public final class ValidateModelTransformationsHandler extends AbstractHandler {
private void clearUUIDSqlString( SqlTransformationMappingRoot mappingRoot ) {
if (mappingRoot != null) {
MappingHelper helper = mappingRoot.getHelper();
if ((helper != null) && (helper instanceof SqlTransformation)) {
SqlTransformation sqlHelper = (SqlTransformation)helper;
if (sqlHelper.isInsertAllowed() && !sqlHelper.isInsertSqlDefault()) {
sqlHelper.setInsertSql(null);
}
if (sqlHelper.isUpdateAllowed() && !sqlHelper.isUpdateSqlDefault()) {
sqlHelper.setUpdateSql(null);
}
if (sqlHelper.isDeleteAllowed() && !sqlHelper.isDeleteSqlDefault()) {
sqlHelper.setDeleteSql(null);
}
}
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
*/
@Override
public Object execute( ExecutionEvent event ) throws ExecutionException {
IEditorPart editor = HandlerUtil.getActiveEditor(event);
// get the currently active ModelObjectEditorPage, ensure its TransformationObjEditorPage
if (editor instanceof MultiPageModelEditor) {
ModelObjectEditorPage editorPage = ((MultiPageModelEditor)editor).getActiveObjectEditor();
if ((editorPage != null) && (editorPage instanceof TransformationObjectEditorPage)) {
((MultiPageModelEditor)editor).closeObjectEditor();
}
}
// the one selected object will be an IFile of a virtual model because of how Command extension is implemented
IStructuredSelection selection = (IStructuredSelection)HandlerUtil.getCurrentSelection(event);
IFile virtualModelFile = (IFile)selection.getFirstElement();
ModelResource virtualModel = null;
try {
ModelResource modelResource = ModelUtil.getModelResource(virtualModelFile, false);
if (ModelUtilities.isVirtual(modelResource)) {
virtualModel = modelResource;
}
} catch (ModelWorkspaceException e) {
UiConstants.Util.log(e);
}
if (virtualModel != null) {
// force the modelEditor open so that changes mark the resource dirty
IResource resource = virtualModel.getResource();
ModelEditorManager.getModelEditorForFile((IFile)resource, true);
final ModelResource viewModel = virtualModel;
final List[] brokenTables = new ArrayList[1];
final WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
@Override
public void execute( IProgressMonitor theMonitor ) {
brokenTables[0] = revalidate(viewModel);
theMonitor.done();
}
};
// run operation
Shell shell = HandlerUtil.getActiveShell(event);
try {
new ProgressMonitorDialog(shell).run(true, true, op);
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
UiConstants.Util.log(e.getTargetException());
}
warnUserAboutInvalidTransformations(shell, brokenTables[0]);
}
return null; // per javadoc
}
private void invalidateSqlRootCache( List mappingRoots ) {
Object nextObj = null;
for (Iterator iter = mappingRoots.iterator(); iter.hasNext();) {
nextObj = iter.next();
if (nextObj instanceof SqlTransformationMappingRoot) {
SqlTransformationMappingRoot mappingRoot = (SqlTransformationMappingRoot)nextObj;
SqlMappingRootCache.invalidateSelectStatus(mappingRoot, false, this);
}
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.core.commands.IHandler#isEnabled()
*/
@Override
public boolean isEnabled() {
return true;
}
private boolean resetTransformation( SqlTransformationMappingRoot mappingRoot,
int cmdType,
QueryValidator qv ) {
String userSqlString = TransformationHelper.getSqlString(mappingRoot, cmdType);
setUserString(mappingRoot, userSqlString, cmdType);
TransformationMappingHelper.reconcileMappingsOnSqlChange(mappingRoot, null);
QueryValidationResult result = qv.validateSql(userSqlString, cmdType, false);
return result.isParsable() && result.isResolvable() && result.isValidatable();
}
List revalidate( ModelResource virtualModel ) {
// Keep list of problems
List brokenSqlTables = new ArrayList();
if (virtualModel != null) {
// shut off transformation notifications
UiPlugin.getDefault().setIgnoreTransformationNotifications(true);
// start txn
boolean requiredStart = ModelerCore.startTxn(true, false, "Revalidate Transformations", this); //$NON-NLS-1$
boolean succeeded = false;
try {
Object nextObj = null;
List transformations = virtualModel.getModelTransformations().getTransformations();
// Clean out the SqlMappingRootCache for these transformations
invalidateSqlRootCache(transformations);
// Iterate all of the transformation mapping roots
for (Iterator iter = transformations.iterator(); iter.hasNext();) {
nextObj = iter.next();
if (TransformationHelper.isSqlTransformationMappingRoot(nextObj)) {
// Get current mapping root and query validator
SqlTransformationMappingRoot mappingRoot = (SqlTransformationMappingRoot)nextObj;
QueryValidator qv = new TransformationValidator(mappingRoot, false);
// Check if INSERT/UPDATE/DELETE should be validated
boolean supportsUpdates = false;
EObject mRootTarget = mappingRoot.getTarget();
SqlAspect sqlAspect = org.teiid.designer.core.metamodel.aspect.sql.SqlAspectHelper.getSqlAspect(mRootTarget);
if (sqlAspect != null && (sqlAspect instanceof SqlTableAspect)) {
supportsUpdates = ((SqlTableAspect)sqlAspect).supportsUpdate(mRootTarget);
}
// Init query valid flags - will be set to false if problems.
boolean selectValid = true;
boolean insertValid = true;
boolean updateValid = true;
boolean deleteValid = true;
// Reset Select
selectValid = resetTransformation(mappingRoot, QueryValidator.SELECT_TRNS, qv);
// Reset Insert, Update, Delete
if (supportsUpdates) {
// RESET INSERT
insertValid = resetTransformation(mappingRoot, QueryValidator.INSERT_TRNS, qv);
// RESET UPDATE
updateValid = resetTransformation(mappingRoot, QueryValidator.UPDATE_TRNS, qv);
// RESET DELETE
deleteValid = resetTransformation(mappingRoot, QueryValidator.DELETE_TRNS, qv);
} else {
clearUUIDSqlString(mappingRoot);
}
// If any of the components have a problem, add to broken table list.
if (!selectValid || !insertValid || !updateValid || !deleteValid) {
brokenSqlTables.add(mRootTarget);
}
}
}
succeeded = true;
} catch (ModelWorkspaceException e) {
UiConstants.Util.log(e);
} finally {
if (requiredStart) {
if (succeeded) {
ModelerCore.commitTxn();
} else {
ModelerCore.rollbackTxn();
}
}
// re-enable transformation notifications
UiPlugin.getDefault().setIgnoreTransformationNotifications(false);
}
}
return brokenSqlTables;
}
private void setUserString( SqlTransformationMappingRoot mappingRoot,
String userSqlStr,
int cmdType ) {
if (cmdType == QueryValidator.SELECT_TRNS) {
TransformationHelper.setSelectSqlUserString(mappingRoot, userSqlStr, false, false, this);
} else if (cmdType == QueryValidator.INSERT_TRNS) {
TransformationHelper.setInsertSqlUserString(mappingRoot, userSqlStr, false, false, this);
} else if (cmdType == QueryValidator.UPDATE_TRNS) {
TransformationHelper.setUpdateSqlUserString(mappingRoot, userSqlStr, false, false, this);
} else if (cmdType == QueryValidator.DELETE_TRNS) {
TransformationHelper.setDeleteSqlUserString(mappingRoot, userSqlStr, false, false, this);
}
}
private void warnUserAboutInvalidTransformations( Shell shell,
List invalidSourceList ) {
if (!invalidSourceList.isEmpty()) {
String title = UiConstants.Util.getString("RevalidateModelTransformationsAction.invalidTransformationsTitle"); //$NON-NLS-1$
String msg = UiConstants.Util.getString("RevalidateModelTransformationsAction.invalidTransformationsMessage"); //$NON-NLS-1$
List copyOfList = new ArrayList(invalidSourceList.size());
for (Iterator iter = invalidSourceList.iterator(); iter.hasNext();) {
Object nextObj = iter.next();
String path = ModelObjectUtilities.getTrimmedFullPath((EObject)nextObj);
String name = ModelerCore.getModelEditor().getName((EObject)nextObj);
String row = path + "/" + name; //$NON-NLS-1$
copyOfList.add(row);
}
ListMessageDialog.openWarning(shell, title, null, msg, copyOfList, null);
}
}
}