blob: 3ff977084098d4e874e76dc4cbc6546ca57eb884 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2018 Fondazione Bruno Kessler.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Luca Cristoforetti - initial API and implementation
******************************************************************************/
package org.polarsys.chess.tradeoffAnalysis.commands;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Class;
import org.polarsys.chess.chessmlprofile.Dependability.DependableComponent.Analysis;
import org.polarsys.chess.chessmlprofile.ParameterizedArchitecture.InstantiatedArchitectureConfiguration;
import org.polarsys.chess.contracts.profile.chesscontract.ContractProperty;
import org.polarsys.chess.contracts.profile.chesscontract.FormalProperty;
import org.polarsys.chess.contracts.profile.chesscontract.util.ContractEntityUtil;
import org.polarsys.chess.contracts.profile.chesscontract.util.EntityUtil;
import org.polarsys.chess.service.core.model.ChessSystemModel;
import org.polarsys.chess.service.core.utils.AnalysisResultUtil;
import org.polarsys.chess.service.gui.utils.SelectionUtil;
import org.polarsys.chess.tradeoffAnalysis.dialogs.ConfigurationSelectionDialog;
import org.polarsys.chess.tradeoffAnalysis.views.TradeoffView;
import org.polarsys.chess.tradeoffAnalysis.views.TradeoffView.Row;
import eu.fbk.eclipse.standardtools.ExecOcraCommands.ui.services.OCRAExecService;
import eu.fbk.eclipse.standardtools.ModelTranslatorToOcra.ui.services.OSSTranslatorServiceUI;
import eu.fbk.eclipse.standardtools.utils.ui.commands.AbstractJobCommand;
import eu.fbk.eclipse.standardtools.utils.ui.dialogs.MessageTimeModelDialog;
import eu.fbk.eclipse.standardtools.utils.ui.utils.DialogUtil;
import eu.fbk.eclipse.standardtools.utils.ui.utils.ErrorsDialogUtil;
import eu.fbk.eclipse.standardtools.utils.ui.utils.OCRADirectoryUtil;
import eu.fbk.tools.adapter.ocra.CheckContractRefinement;
import eu.fbk.tools.adapter.ocra.CheckContractResultBuilder;
import eu.fbk.tools.adapter.ocra.OcraOutput;
import eu.fbk.tools.adapter.results.ContractCheckResult;
import eu.fbk.tools.adapter.results.ModelCheckResult;
/**
* This command triggers the trade-off analysis.
*
* @author cristofo
*
*/
public class TradeoffCommand extends AbstractJobCommand {
private static final Logger logger = Logger.getLogger(TradeoffCommand.class);
private ConfigurationSelectionDialog configurationSelectionDialog;
private SelectionUtil selectionUtil = SelectionUtil.getInstance();
private ContractEntityUtil contractEntityUtil = ContractEntityUtil.getInstance();
private final ErrorsDialogUtil errorsDialogUtil = ErrorsDialogUtil.getInstance();
private DialogUtil dialogUtil = DialogUtil.getInstance();
private OCRAExecService ocraExecService = OCRAExecService.getInstance(ChessSystemModel.getInstance());
private OCRADirectoryUtil ocraDirectoryUtil = OCRADirectoryUtil.getInstance();
private OSSTranslatorServiceUI ocraTranslatorService = OSSTranslatorServiceUI
.getInstance(ChessSystemModel.getInstance());
private Class umlSelectedComponent;
private String checkType;
private EList<InstantiatedArchitectureConfiguration> configurations;
private boolean isDiscreteTime;
private File ossFile;
private boolean goAhead;
// The list of analyses results
private List<AnalysisResult> results;
public TradeoffCommand() {
super("Trade-off Analysis");
}
/**
* Exports to OSS the selected component.
*
* @param isDiscreteTime
* type of time model
* @param event
* the event
* @param monitor
* the monitor
* @return the exported file
* @throws Exception
*/
// Taken from InstantiateArchitectureViaWizard.exportArchitectureAsOssFile()
private File exportArchitectureAsOssFile(boolean isDiscreteTime, ExecutionEvent event, IProgressMonitor monitor)
throws Exception {
final String ossFilepath = ocraDirectoryUtil.getOSSDirPath();
final boolean showPopups = false;
final boolean usexTextValidation = true;
final Class umlSelectedComponent = selectionUtil.getUmlComponentFromSelectedObject(event);
final Resource umlSelectedResource = umlSelectedComponent.eResource();
return ocraTranslatorService.exportRootComponentToOssFile(umlSelectedComponent, umlSelectedResource,
isDiscreteTime, usexTextValidation, showPopups, ossFilepath, monitor);
}
@Override
public void execPreJobOperations(ExecutionEvent event, IProgressMonitor monitor) throws Exception {
umlSelectedComponent = selectionUtil.getUmlComponentFromSelectedObject(event);
goAhead = false;
// The command should be executed only on root components
if (!EntityUtil.getInstance().isSystem(umlSelectedComponent)) {
errorsDialogUtil.showMessage_GenericError("Please select a <<System>> component");
return;
}
final Display defaultDisplay = Display.getDefault();
defaultDisplay.syncExec(new Runnable() {
@Override
public void run() {
configurationSelectionDialog = new ConfigurationSelectionDialog(umlSelectedComponent);
configurationSelectionDialog.open();
}
});
goAhead = configurationSelectionDialog.goAhead();
if (!goAhead) {
return;
}
checkType = configurationSelectionDialog.getCheckType();
configurations = configurationSelectionDialog.getConfigurations();
isDiscreteTime = MessageTimeModelDialog.openQuestion(false);
// Generate the OSS file for the parametrized architecture
ossFile = exportArchitectureAsOssFile(isDiscreteTime, event, monitor);
}
/**
* Converts the EList of parameters to a List.
*
* @param parameters
* the list of parameters
* @return the required List
*/
/*
* private ArrayList<String> prepareParameterValuesAsArrayList(EList<String>
* parameters) { final ArrayList<String> parametersArray = new
* ArrayList<String>();
*
* for (String string : parameters) { parametersArray.add(string); } return
* parametersArray; }
*/
/**
* Navigates the given component to the specified contract and retrieves the
* concerns it addresses.
*
* @param umlSelectedComponent
* the component to navigate
* @param contractName
* the name of the contract to analyse
* @return the concerns addressed
*/
private String getConcerns(Class umlSelectedComponent, String contractName) {
String concerns = null;
// Get the contract properties of the component and look for the correct
// one
final EList<ContractProperty> contractProperties = contractEntityUtil
.getContractProperties(umlSelectedComponent);
for (ContractProperty contractProperty : contractProperties) {
final Class contractPropertyType = (Class) contractProperty.getBase_Property().getType();
if (contractPropertyType.getName().equals(contractName)) {
final FormalProperty assume = contractEntityUtil.getAssumeFromUmlContract(contractPropertyType);
concerns = assume.getConcern().getName();
final FormalProperty guarantee = contractEntityUtil.getGuaranteeFromUmlContract(contractPropertyType);
if (!guarantee.getConcern().getName().equals(concerns)) {
concerns += ", " + guarantee.getConcern().getName();
}
}
}
return concerns;
}
/**
* Takes the result of an analysis an creates an entry row for the table.
*
* @param index
* the number of configuration being parsed
* @param analysisResult
* the analysis result
* @param rows
* the row being populated
* @param labels
* the list of column labels to be populated
* @param concernsRow
* the concerns row to be populated
*/
private void processResult(int index, AnalysisResult analysisResult, Row row, List<String> labels,
Row concernsRow) {
// Open the file containing the results
final File resultFile;
try {
resultFile = new File(analysisResult.getResultFilePath());
} catch (Exception e) {
dialogUtil.showMessage_ExceptionError(e);
e.printStackTrace();
return;
}
// Parse the results file
final CheckContractResultBuilder resultBuilder = new CheckContractResultBuilder();
final OcraOutput ocraOutput = resultBuilder.unmarshalResult(resultFile);
if (ocraOutput == null || ocraOutput.getOcraResult() == null || ocraOutput.getOcraResult().isEmpty()) {
logger.debug("Error while unmarshalling the result. For more info see the console");
return;
}
final ModelCheckResult contractCheckResult = resultBuilder.buildResult(ocraOutput);
if (contractCheckResult == null) {
logger.debug("Internal error while building the result. For more info see the console");
return;
}
final List<ContractCheckResult> contractCheckResults = contractCheckResult.getContractCheckResults();
for (ContractCheckResult result : contractCheckResults) {
if (result.getCheckType().equals("ocra_check_refinement")) {
// Check only the contracts of the root component
if (result.getComponentType().equals(umlSelectedComponent.getName())) {
String contractName = result.getContractName();
// If the configuration is the first, populate also labels
// and concerns
if (index == 0) {
labels.add(contractName);
concernsRow.addResult(getConcerns(umlSelectedComponent, contractName));
}
// Store the result of the check;
final String checkResult = result.getFailed() ? "NOT OK" : "Success";
row.addResult(checkResult);
}
}
}
}
/**
* Fills the table view with the given results.
*
* @param results
* the results of the analyses
*/
private void displayResult(List<AnalysisResult> results) {
final Display display = PlatformUI.getWorkbench().getDisplay();
display.asyncExec(() -> {
try {
final TradeoffView viewPart = (TradeoffView) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage().showView(TradeoffView.ID, null, IWorkbenchPage.VIEW_VISIBLE);
if (viewPart != null) {
// Prepare the names of the fixed columns
final List<String> labels = new ArrayList<String>();
labels.add(configurationSelectionDialog.getCheckType());
labels.add(""); // Hidden field used to store analysis type
labels.add(""); // Hidden field used to store file path
// The rows for the table
final List<Row> rows = new ArrayList<Row>();
// First row is for concerns, will be completed later
final Row concernsRow = new Row("Concerns");
rows.add(concernsRow);
int index = 0;
for (AnalysisResult analysisResult : results) {
// Create a row foreach analysis
final Row configuration = new Row(analysisResult.getConfigurationName());
rows.add(configuration);
configuration.setAnalysisName(checkType);
configuration.setResultFilePath(analysisResult.getResultFilePath());
processResult(index++, analysisResult, configuration, labels, concernsRow);
}
// Create the columns names for the table
viewPart.createColumns(viewPart.getViewer(), labels);
// Check to see if everything is fine
final TableViewer tableViewer = viewPart.getViewer();
final IContentProvider provider = tableViewer.getContentProvider();
if (provider == null) {
return;
}
// Set the values for the table
tableViewer.setInput(rows);
tableViewer.refresh();
// Switch to the view
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().activate(viewPart);
}
} catch (Exception e) {
dialogUtil.showMessage_ExceptionError(e);
e.printStackTrace();
}
});
}
@Override
public void execJobCommand(ExecutionEvent event, IProgressMonitor monitor) throws Exception {
if (!goAhead || ossFile == null) {
return;
}
// The list of analyses results
results = new ArrayList<AnalysisResult>();
if (configurations.size() > 0) {
if (checkType.equals(ConfigurationSelectionDialog.CHECK_CONTRACT_REFINEMENT)) {
// Change the type to the actual function name used
checkType = CheckContractRefinement.FUNCTION_NAME;
for (InstantiatedArchitectureConfiguration configuration : configurations) {
final String configurationName = configuration.getBase_Property().getName();
final File parametersValuesFile = ocraExecService
.prepareParameterValuesFile(configuration.getParameterList(), ossFile.getName());
final File instantiatedOssFile = ocraExecService.executeInstantiateArchitecture(configurationName,
ossFile, parametersValuesFile, 1, isDiscreteTime, monitor);
final String resultFilePath = ocraDirectoryUtil
.getCommandCheckRefinementResultPath(configurationName);
final boolean internalExecution = true; // Wait to finish
// before saving
// result
if (ocraExecService.executeCheckContractRefinement(instantiatedOssFile, isDiscreteTime,
resultFilePath, monitor, internalExecution)) {
// Store the result
final AnalysisResult result = new AnalysisResult(configuration, resultFilePath);
results.add(result);
}
}
displayResult(results);
}
}
}
/**
* Small class to store the configuration name and its result file.
*
* @author cristofo
*
*/
protected class AnalysisResult {
private InstantiatedArchitectureConfiguration configuration;
private String resultFilePath;
public AnalysisResult(InstantiatedArchitectureConfiguration configuration, String resultFilePath) {
this.configuration = configuration;
this.resultFilePath = resultFilePath;
}
public InstantiatedArchitectureConfiguration getConfiguration() {
return configuration;
}
public String getConfigurationName() {
return configuration.getBase_Property().getName();
}
public void setConfiguration(InstantiatedArchitectureConfiguration configurationName) {
this.configuration = configurationName;
}
public String getResultFilePath() {
return resultFilePath;
}
public void setResultFilePath(String resultFilePath) {
this.resultFilePath = resultFilePath;
}
}
@Override
public void execPostJobOperations(ExecutionEvent event, NullProgressMonitor nullProgressMonitor) throws Exception {
if (!goAhead || ossFile == null) {
return;
}
for(AnalysisResult currResult : results){
// Store the result
AnalysisResultUtil.getInstance().createOrUpdateAnalysisContext(Analysis.CONTRACT_REFINEMENT_ANALYSIS, ECollections.emptyEList() , currResult.getResultFilePath(),false,
umlSelectedComponent,currResult.getConfiguration(), null);
}
}
}