/** * Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis, * Rick Salay. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alessio Di Sandro - Implementation. */ package edu.toronto.cs.se.mmint.mid.operator.impl; import edu.toronto.cs.se.mmint.MIDTypeHierarchy; import edu.toronto.cs.se.mmint.MIDTypeRegistry; import edu.toronto.cs.se.mmint.MMINT; import edu.toronto.cs.se.mmint.MMINTException; import edu.toronto.cs.se.mmint.mid.GenericElement; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.MIDFactory; import edu.toronto.cs.se.mmint.mid.MIDLevel; import edu.toronto.cs.se.mmint.mid.MIDPackage; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.ModelEndpoint; import edu.toronto.cs.se.mmint.mid.editor.Diagram; import edu.toronto.cs.se.mmint.mid.operator.GenericEndpoint; import edu.toronto.cs.se.mmint.mid.operator.Operator; import edu.toronto.cs.se.mmint.mid.operator.OperatorFactory; import edu.toronto.cs.se.mmint.mid.operator.OperatorGeneric; import edu.toronto.cs.se.mmint.mid.operator.OperatorInput; import edu.toronto.cs.se.mmint.mid.operator.OperatorPackage; import edu.toronto.cs.se.mmint.mid.operator.WorkflowOperator; import edu.toronto.cs.se.mmint.mid.relationship.ModelRel; import edu.toronto.cs.se.mmint.mid.ui.GMFUtils; import edu.toronto.cs.se.mmint.mid.utils.FileUtils; import edu.toronto.cs.se.mmint.mid.utils.MIDRegistry; import edu.toronto.cs.se.mmint.mid.utils.MIDTypeFactory; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.runtime.IStatus; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.gmf.runtime.notation.View; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; /** * <!-- begin-user-doc --> * An implementation of the model object '<em><b>Workflow Operator</b></em>'. * <!-- end-user-doc --> * <p> * The following features are implemented: * </p> * <ul> * <li>{@link edu.toronto.cs.se.mmint.mid.operator.impl.WorkflowOperatorImpl#getMidUri <em>Mid Uri</em>}</li> * </ul> * * @generated */ public class WorkflowOperatorImpl extends OperatorImpl implements WorkflowOperator { /** * The default value of the '{@link #getMidUri() <em>Mid Uri</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getMidUri() * @generated * @ordered */ protected static final String MID_URI_EDEFAULT = null; /** * The cached value of the '{@link #getMidUri() <em>Mid Uri</em>}' attribute. * <!-- begin-user-doc --> * <!-- end-user-doc --> * @see #getMidUri() * @generated * @ordered */ protected String midUri = MID_URI_EDEFAULT; /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated NOT */ public WorkflowOperatorImpl() { super(); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override protected EClass eStaticClass() { return OperatorPackage.Literals.WORKFLOW_OPERATOR; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public String getMidUri() { return midUri; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public void setMidUri(String newMidUri) { String oldMidUri = midUri; midUri = newMidUri; if (eNotificationRequired()) eNotify(new ENotificationImpl(this, Notification.SET, OperatorPackage.WORKFLOW_OPERATOR__MID_URI, oldMidUri, midUri)); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public MID getWorkflowMID() throws MMINTException { MMINTException.mustBeType(this); try { return (MID) FileUtils.readModelFileInState(this.getMidUri()); } catch (Exception e) { return null; } } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ public MID getInstanceMID() throws MMINTException { MMINTException.mustBeInstance(this); try { return (MID) FileUtils.readModelFile(this.getMidUri(), true); } catch (Exception e) { return null; } } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public Object eGet(int featureID, boolean resolve, boolean coreType) { switch (featureID) { case OperatorPackage.WORKFLOW_OPERATOR__MID_URI: return getMidUri(); } return super.eGet(featureID, resolve, coreType); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public void eSet(int featureID, Object newValue) { switch (featureID) { case OperatorPackage.WORKFLOW_OPERATOR__MID_URI: setMidUri((String)newValue); return; } super.eSet(featureID, newValue); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public void eUnset(int featureID) { switch (featureID) { case OperatorPackage.WORKFLOW_OPERATOR__MID_URI: setMidUri(MID_URI_EDEFAULT); return; } super.eUnset(featureID); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public boolean eIsSet(int featureID) { switch (featureID) { case OperatorPackage.WORKFLOW_OPERATOR__MID_URI: return MID_URI_EDEFAULT == null ? midUri != null : !MID_URI_EDEFAULT.equals(midUri); } return super.eIsSet(featureID); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public Object eInvoke(int operationID, EList<?> arguments) throws InvocationTargetException { switch (operationID) { case OperatorPackage.WORKFLOW_OPERATOR___GET_WORKFLOW_MID: try { return getWorkflowMID(); } catch (Throwable throwable) { throw new InvocationTargetException(throwable); } case OperatorPackage.WORKFLOW_OPERATOR___GET_INSTANCE_MID: try { return getInstanceMID(); } catch (Throwable throwable) { throw new InvocationTargetException(throwable); } } return super.eInvoke(operationID, arguments); } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * @generated */ @Override public String toStringGen() { if (eIsProxy()) return super.toString(); StringBuffer result = new StringBuffer(super.toString()); result.append(" (midUri: "); result.append(midUri); result.append(')'); return result.toString(); } /** * @generated NOT */ @Override public String toString() { return "[workflow] " + super.toString(); } /** * Adds a subtype of this workflow operator type to the Type MID. * * @param newOperatorType * The new operator type to be added. * @param newOperatorTypeName * The name of the new operator type. * @param workflowMIDUri * The uri of the Workflow MID that implements the new operator. * @throws MMINTException * If the uri of the new operator type is already registered in the Type MID, or if the Workflow MID * cannot be read or copied. * @generated NOT */ @Override protected void addSubtype(Operator newOperatorType, String newOperatorTypeName, String workflowMIDUri) throws MMINTException { MID typeMID = this.getMIDContainer(); super.addSubtype(newOperatorType, this, null, newOperatorTypeName); try { MID workflowMID; String newWorkflowMIDUri; if (FileUtils.isFileOrDirectoryInState(workflowMIDUri)) { // just recreating this subtype at startup workflowMID = (MID) FileUtils.readModelFileInState(workflowMIDUri); newWorkflowMIDUri = workflowMIDUri; } else { // make a copy of the Workflow MID files workflowMID = (MID) FileUtils.readModelFile(workflowMIDUri, true); newWorkflowMIDUri = newOperatorTypeName + MMINT.MODEL_FILEEXTENSION_SEPARATOR + MIDPackage.eNAME; FileUtils.writeModelFileInState(workflowMID, newWorkflowMIDUri); FileUtils.copyTextFileAndReplaceText( FileUtils.prependWorkspacePathToUri(workflowMIDUri + GMFUtils.DIAGRAM_SUFFIX), FileUtils.prependStatePathToUri(newWorkflowMIDUri + GMFUtils.DIAGRAM_SUFFIX), FileUtils.getLastSegmentFromUri(workflowMIDUri), newWorkflowMIDUri, false); } ((WorkflowOperator) newOperatorType).setMidUri(newWorkflowMIDUri); MIDTypeFactory.addOperatorType(newOperatorType, typeMID); Map<Model, String> inoutWorkflowModels = new HashMap<>(); for (Model workflowModel : workflowMID.getModels()) { // first pass: identify inputs and outputs boolean isInput = MIDRegistry.getOutputOperators(workflowModel, workflowMID).isEmpty(); // no operator generated this model if (isInput) { inoutWorkflowModels.put(workflowModel, OperatorPackage.eINSTANCE.getOperator_Inputs().getName()); continue; // an input can't be output too } boolean isOutput = MIDRegistry.getInputOperators(workflowModel, workflowMID).isEmpty(); // no operator has this model as input if (isOutput) { inoutWorkflowModels.put(workflowModel, OperatorPackage.eINSTANCE.getOperator_Outputs().getName()); if (workflowModel instanceof ModelRel) { // an output model rel needs its endpoint models as output too for (ModelEndpoint outModelEndpoint : ((ModelRel) workflowModel).getModelEndpoints()) { Model outModel = outModelEndpoint.getTarget(); if (inoutWorkflowModels.containsKey(outModel)) { continue; } inoutWorkflowModels.put(outModel, OperatorPackage.eINSTANCE.getOperator_Outputs().getName()); } } } } for (Entry<Model, String> inoutWorkflowModel : inoutWorkflowModels.entrySet()) { // second pass: create endpoints for operator type Model workflowModel = inoutWorkflowModel.getKey(); ModelEndpoint newModelTypeEndpoint = MIDFactory.eINSTANCE.createModelEndpoint(); Model modelType = typeMID.getExtendibleElement(workflowModel.getMetatypeUri()); MIDTypeFactory.addType(newModelTypeEndpoint, null, newOperatorType.getUri() + MMINT.URI_SEPARATOR + workflowModel.getUri(), workflowModel.getName(), typeMID); newModelTypeEndpoint.setDynamic(true); MIDTypeFactory.addModelTypeEndpoint(newModelTypeEndpoint, modelType, newOperatorType, inoutWorkflowModel.getValue()); } } catch (Exception e) { super.delete(newOperatorType.getUri(), typeMID); throw new MMINTException("Error copying the Workflow MID", e); } } /** * @generated NOT */ public void deleteType() throws MMINTException { super.deleteType(); FileUtils.deleteFileInState(this.getMidUri()); FileUtils.deleteFileInState(this.getMidUri() + GMFUtils.DIAGRAM_SUFFIX); } /** * Opens the MID with the intermediate models generated by this workflow operator instance, if it exists. * * @throws Exception * If this is not a workflow operator instance, or if the MID diagram can't be opened. * @generated NOT */ @Override public void openType() throws Exception { MMINTException.mustBeType(this); if (MIDTypeHierarchy.isRootType(this.getSupertype())) { super.openType(); return; } Diagram midDiagramType = MIDTypeRegistry.getMIDDiagramType(); FileUtils.openEclipseEditorInState(this.getMidUri() + GMFUtils.DIAGRAM_SUFFIX, midDiagramType.getId()); } /** * @generated NOT */ @Override protected void addInstance(@NonNull Operator newOperator, @NonNull MIDLevel midLevel, @Nullable MID instanceMID) { super.addInstance(newOperator, midLevel, instanceMID); if (instanceMID == null) { return; } String operatorInstanceMIDUri = FileUtils.getUniqueUri( FileUtils.replaceFileNameInUri( MIDRegistry.getModelAndModelElementUris(instanceMID, MIDLevel.INSTANCES)[0], newOperator.getName()), true, false); MID operatorInstanceMID = MIDFactory.eINSTANCE.createMID(); operatorInstanceMID.setLevel(MIDLevel.INSTANCES); Model midModelType = MIDTypeRegistry.getMIDModelType(); Diagram midDiagramType = MIDTypeRegistry.getMIDDiagramType(); try { FileUtils.writeModelFile(operatorInstanceMID, operatorInstanceMIDUri, true); ((WorkflowOperator) newOperator).setMidUri(operatorInstanceMIDUri); GMFUtils.createGMFDiagram( operatorInstanceMIDUri, operatorInstanceMIDUri + GMFUtils.DIAGRAM_SUFFIX, midModelType.getName(), MIDTypeRegistry.getTypeBundle(midDiagramType.getUri()).getSymbolicName(), true); } catch (Exception e) { MMINTException.print(IStatus.WARNING, "Can't store the Instance MID to contain this workflow operator's intermediate results, skipping it", e); } } /** * @generated NOT */ @Override public void deleteInstance() throws MMINTException { super.deleteInstance(); FileUtils.deleteFile(this.getMidUri(), true); FileUtils.deleteFile(this.getMidUri() + GMFUtils.DIAGRAM_SUFFIX, true); } /** * Runs this workflow operator instance, i.e. executes its Workflow MID implementation. * * @param inputsByName * The input model instances, identified by their formal parameter name, i.e. the models in the Workflow * MID that are not output of any operator. * @param genericsByName * The generic types, identified by their metatype name. * @param outputMIDsByName * The instance MIDs where the output models are created, identified by the output name. A null Instance * MID means that the output model isn't added to it. * @return The output model instances, identified by their name, i.e. the models in the Workflow MID that are not * input of any operator. * @throws Exception * If something went wrong running the operator. * @generated NOT */ @Override public Map<String, Model> run(Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { MMINTException.mustBeInstance(this); // workflowMID is executed, intermediate models are stored in instanceMID, outputs in outputMIDsByName MID workflowMID = ((WorkflowOperator) this.getMetatype()).getWorkflowMID(); MID instanceMID = this.getInstanceMID(); Map<String, Model> allModelsByName = new HashMap<>(inputsByName); // create shortcuts to input models String instanceMIDUri = this.getMidUri(); String instanceMIDDiagramUri = instanceMIDUri + GMFUtils.DIAGRAM_SUFFIX; View instanceMIDDiagramRoot = (View) FileUtils.readModelFile(instanceMIDDiagramUri, true); Model midModelType = MIDTypeRegistry.getMIDModelType(); Diagram midDiagramType = MIDTypeRegistry.getMIDDiagramType(); String midDiagramPluginId = MIDTypeRegistry.getTypeBundle(midDiagramType.getUri()).getSymbolicName(); if (instanceMID != null) { for (Model inputModel : inputsByName.values()) { GMFUtils.createGMFNodeShortcut(inputModel, instanceMIDDiagramRoot, midDiagramPluginId, midModelType.getName()); } } // the order of operator creation in the workflow is a safe order of execution too Map<String, Model> outputsByName = new HashMap<>(); for (Operator workflowOperator : workflowMID.getOperators()) { EList<OperatorInput> workflowInputs = new BasicEList<>(); for (ModelEndpoint inputModelEndpoint : workflowOperator.getInputs()) { OperatorInput workflowInput = OperatorFactory.eINSTANCE.createOperatorInput(); workflowInput.setModelTypeEndpoint(inputModelEndpoint.getMetatype()); workflowInput.setModel(allModelsByName.get(inputModelEndpoint.getTargetUri())); workflowInputs.add(workflowInput); } EList<OperatorGeneric> workflowGenerics = new BasicEList<>(); for (GenericEndpoint workflowGenericEndpoint : workflowOperator.getGenerics()) { OperatorGeneric workflowGeneric = OperatorFactory.eINSTANCE.createOperatorGeneric(); workflowGeneric.setGenericSuperTypeEndpoint(workflowGenericEndpoint.getMetatype()); workflowGeneric.setGeneric(workflowGenericEndpoint.getTarget()); workflowGenerics.add(workflowGeneric); } Map<String, MID> workflowOutputMIDsByName = new HashMap<>(); for (ModelEndpoint outputModelEndpoint : workflowOperator.getOutputs()) { MID outputMID = outputMIDsByName.getOrDefault(outputModelEndpoint.getTargetUri(), instanceMID); workflowOutputMIDsByName.put(outputModelEndpoint.getName(), outputMID); } Map<String, Model> workflowOutputsByName = workflowOperator.getMetatype().startInstance( workflowInputs, null, workflowGenerics, workflowOutputMIDsByName, instanceMID) .getOutputsByName(); for (ModelEndpoint outputModelEndpoint : workflowOperator.getOutputs()) { Model outputModel = workflowOutputsByName.get(outputModelEndpoint.getName()); allModelsByName.put(outputModelEndpoint.getTargetUri(), outputModel); if (workflowOutputMIDsByName.get(outputModelEndpoint.getName()) != instanceMID) { // final outputs outputsByName.put(outputModelEndpoint.getTargetUri(), outputModel); // create shortcuts to output models, or make a copy of output model rels if (instanceMID != null) { if (outputModel instanceof ModelRel) { ((ModelRel) outputModel).getMetatype().copyInstance(outputModel, outputModel.getName(), instanceMID); } else { GMFUtils.createGMFNodeShortcut(outputModel, instanceMIDDiagramRoot, midDiagramPluginId, midModelType.getName()); instanceMID.getExtendibleTable().put(outputModel.getUri(), outputModel); } } } } } if (instanceMID != null) { FileUtils.writeModelFile(instanceMID, instanceMIDUri, true); FileUtils.writeModelFile(instanceMIDDiagramRoot, instanceMIDDiagramUri, true); } return outputsByName; } /** * Opens the MID with the intermediate models generated by this workflow operator instance, if it exists. * * @throws Exception * If this is not a workflow operator instance, or if the MID diagram can't be opened. * @generated NOT */ @Override public void openInstance() throws Exception { MMINTException.mustBeInstance(this); if (FileUtils.isFile(this.getMidUri(), true)) { Diagram midDiagramType = MIDTypeRegistry.getMIDDiagramType(); FileUtils.openEclipseEditor(this.getMidUri() + GMFUtils.DIAGRAM_SUFFIX, midDiagramType.getId(), true); } } } //WorkflowOperatorImpl