| /******************************************************************************* |
| * 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); |
| } |
| |
| } |
| } |