CHESSIoT_Dev_old-master/org.polarsys.chess.m2m/src/org/polarsys/chess/m2m/handlers/QVToUIHandlerEnd2End.java
/*
-----------------------------------------------------------------------
--          			CHESS M2M plugin							 --
--                                                                   --
--                    Copyright (C) 2011-2012                        --
--                 University of Padova, ITALY                       --
--                                                                   --
-- Authors: -Alessandro Zovi         azovi@math.unipd.it 
--          -Intecs
--                                                                   --
-- 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-v20.html                         --
-----------------------------------------------------------------------
*/

package org.polarsys.chess.m2m.handlers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.polarsys.chess.chessmlprofile.Predictability.DeploymentConfiguration.HardwareBaseline.CH_HwProcessor;
import org.polarsys.chess.chessmlprofile.Predictability.RTComponentModel.CHRtPortSlot;
import org.polarsys.chess.core.util.CHESSProjectSupport;
import org.polarsys.chess.core.util.uml.ResourceUtils;
import org.polarsys.chess.core.util.uml.UMLUtils;
import org.polarsys.chess.core.views.ViewUtils;
import org.polarsys.chess.m2m.Activator;
import org.polarsys.chess.m2m.transformations.PIMPSMTransformationEnd2End;
import org.polarsys.chess.m2m.transformations.TransUtil;
import org.polarsys.chess.m2m.transformations.TransformationResultsData;
import org.polarsys.chess.m2m.ui.AnalysisContextSelectionDialog;
import org.polarsys.chess.m2m.ui.End2EndResultDialog;
import org.polarsys.chess.service.gui.utils.CHESSEditorUtils;
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.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.m2m.internal.qvt.oml.emf.util.ModelContent;
import org.eclipse.papyrus.MARTE.MARTE_AnalysisModel.GQAM.GaWorkloadBehavior;
import org.eclipse.papyrus.MARTE.MARTE_AnalysisModel.SAM.SaAnalysisContext;
import org.eclipse.papyrus.MARTE.MARTE_AnalysisModel.SAM.SaEndtoEndFlow;
import org.eclipse.papyrus.MARTE.MARTE_Foundations.Alloc.Assign;
import org.eclipse.papyrus.editor.PapyrusMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityNode;
import org.eclipse.uml2.uml.CallBehaviorAction;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Stereotype;


/**
 * The Class QVToUIHandlerEnd2End realizes the handler for the end-to-end analysis command.
 * @since 0.9
 */
public class QVToUIHandlerEnd2End extends AbstractHandler {

	/** The Constant SAANALYSISCONTEXT. */
	private static final String SAANALYSISCONTEXT = "MARTE::MARTE_AnalysisModel::SAM::SaAnalysisContext";
	
	/** The Constant SAENDTOENDFLOW. */
	private static final String SAENDTOENDFLOW = "MARTE::MARTE_AnalysisModel::SAM::SaEndtoEndFlow";
	
	/** The active shell. */
	private Shell activeShell = null;
	
	/** The in resource. */
	private Resource inResource = null;
	
	/** The context class. */
	private Class contextClass;
	
	/** The deadline. */
	private String deadline;
	
	/** The scenario. */
	private String scenario;
	
	/** The sa analysis name. */
	private String saAnalysisName;
	
	/** The sa e2 e flow name. */
	private String saE2EFlowName;
	
	/** The sa e2 e flow. */
	private SaEndtoEndFlow saE2EFlow;
	
	/** The sa analysis ctx. */
	private SaAnalysisContext saAnalysisCtx;
	
	/** The psm package name. */
	private String psmPackageName;
	
	/**
	 * Gets the active project.
	 *
	 * @param editor the editor
	 * @return the active project
	 */
	private IProject getActiveProject(IEditorPart editor) {
		IFileEditorInput input = (IFileEditorInput) editor.getEditorInput();
		IFile file = input.getFile();
		return file.getProject();
	}

	/**
	 * Executes the end-to-end response time analysis and shows the results.
	 * The end-to-end analysis context to be analyzed is asked to the user through a dedicated dialog.
	 * 
	 *
	 * @param event the event resulting from the command invocation
	 * @return null
	 * @throws ExecutionException the execution exception
	 * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
	 * @see org.polarsys.chess.m2m.ui.AnalysisContextSelectionDialog
	 */
	public Object execute(final ExecutionEvent event) throws ExecutionException {
		final IEditorPart editor = HandlerUtil.getActiveEditor(event);
		if (!(CHESSEditorUtils.isCHESSProject(editor)))
			return null;

		IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
		activeShell = window.getShell();

		try {
			inResource = ResourceUtils.getUMLResource(((PapyrusMultiDiagramEditor) editor).getServicesRegistry());
		} catch (ServiceException e) {
			e.printStackTrace();
		}

		//open a dialog to select the end-to-end analysis context to be analyzed
		//first get all the classes stereotyped as SaAnalysisContext
		final List<Class> selection = new ArrayList<Class>();
		final Model model = (Model) inResource.getContents().get(0);
		EList<Element> elemList = model.allOwnedElements();
		for (Element elem : elemList) {
			//we're looking for a class stereotyped <<saAnalysisContext>> and NOT in PSM
			if(elem instanceof Class && elem.getAppliedStereotype(SAANALYSISCONTEXT) != null
					&& !ViewUtils.isPSMView(ViewUtils.getView(elem))){
				//as additional constraint, at least one workload is specified
				SaAnalysisContext saAnalysisCtx = (SaAnalysisContext) elem.getStereotypeApplication
						(elem.getAppliedStereotype(SAANALYSISCONTEXT));		
				if(saAnalysisCtx.getWorkload().size() > 0){
					selection.add((Class) elem);
				}
			}
		}
		if(selection.size() == 0){
			MessageDialog.openWarning(activeShell, "CHESS", "no suitable analysis contexts in the model");
			return null;
		}
		//then open the dialog
		String contextQN = null;
		AnalysisContextSelectionDialog dialog = new AnalysisContextSelectionDialog(activeShell, selection, "Select End-To-End Context to analyze");
		if (dialog.open() == Window.OK) {
			contextQN = dialog.getContext();
			if(contextQN == null || contextQN.isEmpty()){
				return null;
			}
			for (Element elem : model.allOwnedElements()){
				if(elem.getAppliedStereotype(SAANALYSISCONTEXT) != null &&
						((NamedElement) elem).getQualifiedName().equals(contextQN)){
					contextClass = (Class) elem;
				}
			}
		}else{
			return null;
		}
		
		saAnalysisName = contextClass.getQualifiedName();
		psmPackageName = contextClass.getName() +"_PSM";
		Stereotype stereo = contextClass.getAppliedStereotype(SAANALYSISCONTEXT);
		saAnalysisCtx = (SaAnalysisContext) contextClass.getStereotypeApplication(stereo);		
		
		EList<GaWorkloadBehavior> workloadList = saAnalysisCtx.getWorkload();
		//assume there's only one workload
		if(workloadList.size() != 1){
			return null;
		}
		GaWorkloadBehavior workload = workloadList.get(0);
		NamedElement nelem = workload.getBase_NamedElement();
		if (!(nelem instanceof Activity)){
			return null;
		}
		Activity workloadActivity = (Activity) nelem;
		saE2EFlowName = workloadActivity.getQualifiedName();
		//check that the activity is also a SaEndToEndFlow (assumption)
		stereo = workloadActivity.getApplicableStereotype(SAENDTOENDFLOW);
		saE2EFlow = (SaEndtoEndFlow) workloadActivity.getStereotypeApplication(stereo);
		//deadline is to be passed to the QVTO transformation
		deadline = saE2EFlow.getEnd2EndD().get(0); //note: in MARTE this relationship is [0..1] not [0..*] as in Papyrus
		//assume the activity has exactly one callbehaviour node
		CallBehaviorAction callbehaviour = null;
		EList<ActivityNode> nodes = workloadActivity.getNodes();
		for (ActivityNode activityNode : nodes) {
			if(activityNode instanceof CallBehaviorAction){
				callbehaviour = (CallBehaviorAction)activityNode;
			}
		}
		
		if (!(callbehaviour.getBehavior() instanceof Interaction)){
			return null;
		}
		//scenario is to be passed to the QVTO transformation
		final Interaction interaction = ((Interaction) callbehaviour.getBehavior());
		scenario = interaction .getQualifiedName();
		
		final Job job = new Job("Transforming") {
			protected IStatus run(IProgressMonitor monitor) {
				try {
					
					TransformationResultsData result =null;
					try {
					
						result = QVToUIHandlerEnd2End.this.executeTimingAnalysis(editor, monitor);
						//Reopen the editor
						CHESSEditorUtils.reopenEditor(editor, false);
					} catch (Exception e) {
						throw e;
					} finally {
						getActiveProject(editor).refreshLocal(IResource.DEPTH_INFINITE, monitor);
						
					}
					
					//open sched analysis result
					
					try {
						//can active editor be different from just reopened CHESS ones? it should be not the case given that it has been just reopened
						//inResource = ResourceUtils.getUMLResource(((CHESSEditor) editor).getServicesRegistry());
						//Model model = (Model) inResource.getContents().get(0);
						
						ModelContent inModel = TransUtil.loadModel(result.umlFile);
						Model model = (Model) inModel.getContent().get(0);
						
						openE2EAnalysisReport(model, saAnalysisName, interaction);
					} catch (Exception e) {
						e.printStackTrace();
						throw new Exception("Unable to load the model and so open the schedAnalysisReport");
					}

		
				} catch (Exception e) {
					e.printStackTrace();
					return new Status(Status.ERROR, Activator.PLUGIN_ID, 1,
							"Error in transformation "+ e.getMessage(), null);
				}
				if (monitor.isCanceled())
					return Status.CANCEL_STATUS;
				return Status.OK_STATUS;
			}
		};
		job.addJobChangeListener(new JobChangeAdapter() {
			public void done(IJobChangeEvent event) {
				if (event.getResult().isOK())
					CHESSProjectSupport.printlnToCHESSConsole("Job completed successfully");
				else
					CHESSProjectSupport.printlnToCHESSConsole("Job did not complete successfully");
			}
		});
		job.setUser(true);
		job.setPriority(Job.SHORT);
		job.schedule();
		return null;
	}
	
	/**
	 * Collects all the needed information and invokes the PIMPSMTransformationEnd2End.performTimingAnalysisWithMAST method
	 *
	 * @param editor the current active editor
	 * @param monitor the progress monitor
	 * @return the string resulting from the MAST execution (i.e. the system is/not schedulable) and the modified model
	 * @throws Exception the exception
	 * @see org.polarsys.chess.m2m.transformations.PIMPSMTransformationEnd2End#performTimingAnalysisWithMAST(PapyrusMultiDiagramEditor, IFile, IProgressMonitor)
	 */
	public TransformationResultsData executeTimingAnalysis(IEditorPart editor, IProgressMonitor monitor) throws Exception {
		monitor.beginTask("Transforming", 4);
		if (!(CHESSEditorUtils.isCHESSProject(editor)))
			return null;

		IFile inputFile = CHESSProjectSupport.resourceToFile(inResource);
		
		//finally call the transformation
		PIMPSMTransformationEnd2End t = new PIMPSMTransformationEnd2End();
		t.setFolder(TransUtil.TRANSFORMATIONS_DIR_E2E);
		Map<String, String> configProps = new HashMap<String, String>();
		configProps.put("deadline", deadline);
		configProps.put("scenario", scenario);
		configProps.put("saAnalysis",saAnalysisName);
		configProps.put("saE2EFlow", saE2EFlowName);
		configProps.put("analysisType", "EndToEnd");
		t.setConfigProperty(configProps);
		t.setPsmPackageName(psmPackageName);
		TransformationResultsData result = t.performTimingAnalysisWithMAST((PapyrusMultiDiagramEditor) editor, inputFile, monitor);
				
		return result;
	}
	
	/**
	 * Opens the end-to-end analysis report dialog.
	 *
	 * @param model the model
	 * @param saAnalysisName the sa analysis name
	 * @param interaction the interaction
	 */
	public void openE2EAnalysisReport(final Model model, String saAnalysisName, Interaction interaction){
		//get all the e2e analysis result info from the model and open a simple, user-friendly report
		SaAnalysisContext saAnCtx = null;
		SaEndtoEndFlow saflow = null;
		Package anView = (Package) ViewUtils.getCHESSRtAnalysisPackage(model);
		for (Element elem : anView.allOwnedElements()) {
			if(elem instanceof Class && ((Class)elem).getQualifiedName().equals(saAnalysisName)){
				saAnCtx = UMLUtils.getStereotypeApplication(elem, SaAnalysisContext.class);
				if(saAnCtx.getWorkload().size() > 0){
					saflow = UMLUtils.getStereotypeApplication(saAnCtx.getWorkload().get(0).getBase_NamedElement(), SaEndtoEndFlow.class);
				}
			}
		}
		
		EList<Message> messages = interaction.getMessages();
		final List<Operation> e2eOperations = new ArrayList<Operation>();
		for (Message msg : messages) {
			Operation op = (Operation) msg.getSignature();
			if (op.eIsProxy()){
				op = (Operation) EcoreUtil.resolve(op, model.eResource().getResourceSet());
			}
			e2eOperations.add(op);
		}
		final List<CH_HwProcessor> cpus = new ArrayList<CH_HwProcessor>();
		final List<CHRtPortSlot> specifications = new ArrayList<CHRtPortSlot>();
		final List<Assign> assigns = new ArrayList<Assign>();
		for (Element elem : model.allOwnedElements()) {
			CHRtPortSlot chrtSlot = UMLUtils.getStereotypeApplication(elem, CHRtPortSlot.class);
			//if(chrtSlot != null && UMLUtils.getStereotypeApplication(chrtSlot.getBase_Slot().getOwner(), IdentifInstance.class) != null){
			if(chrtSlot != null){
				specifications.add(chrtSlot);
			}
			if(elem instanceof InstanceSpecification){
				CH_HwProcessor chHwProc = UMLUtils.getStereotypeApplication(elem, CH_HwProcessor.class);
				if(chHwProc != null){
					cpus.add(chHwProc);
				}
			}
			
			Assign assign = UMLUtils.getStereotypeApplication(elem, Assign.class);
			if(assign != null){
				assigns.add(assign);
			}
		};	
		launchDialog(model, cpus, saAnCtx, saflow, e2eOperations, assigns, specifications);
	}
	
	/**
	 * Launch dialog.
	 *
	 * @param model the model
	 * @param cpus the cpus
	 * @param saAnCtx the sa an ctx
	 * @param saflow the saflow
	 * @param e2eOperations the e2e operations
	 * @param assigns the assigns
	 * @param specifications the specifications
	 */
	private static void launchDialog(final Model model, final List<CH_HwProcessor> cpus, final SaAnalysisContext saAnCtx, final SaEndtoEndFlow saflow, final List<Operation> e2eOperations, final List<Assign> assigns, final List<CHRtPortSlot> specifications){
		final Display display = PlatformUI.getWorkbench().getDisplay();
		display.asyncExec(new Runnable() {
			@Override
			public void run() {
				Shell shell = new Shell(display);
				End2EndResultDialog e2eDialog = new End2EndResultDialog(shell, model);
				e2eDialog.setCpus(cpus);
				e2eDialog.setSpecifications(specifications);
				e2eDialog.setSaAnalysisCtx(saAnCtx);
				e2eDialog.setSaE2EFlow(saflow);
				e2eDialog.setMessages(e2eOperations);
				e2eDialog.setAssigns(assigns);
				if (e2eDialog.open() == Window.OK) {
				    System.out.println("OK");
				}
			}
		});
	}
	

}
