Commit 6bd8bc8e authored by Simon Barner's avatar Simon Barner

Merge branch 'master' of https://git.fortiss.org/af3/af3.git into 3873

parents dd40c044 2cf7d54a
......@@ -27,6 +27,15 @@
</modelElementClass>
</modelEditorBinding>
</extension>
<extension
point="org.fortiss.tooling.kernel.ui.modelEditorBinding">
<modelEditorBinding
binding="org.fortiss.af3.cosimulation.ui.editor.fx.ExternalSpecificationFXEditorBinding">
<modelElementClass
modelElementClass="org.fortiss.af3.component.model.IReadOnlyBehaviorSpecification">
</modelElementClass>
</modelEditorBinding>
</extension>
<extension
point="org.fortiss.tooling.kernel.ui.contextMenuContribution">
<contextMenuContribution
......
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<TitledPane text="External Behavior Specification" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<HBox prefHeight="122.0" prefWidth="488.0">
<children>
<Label prefHeight="24.0" prefWidth="34.0" text="Path:">
<font>
<Font size="14.0" />
</font>
</Label>
<TextField fx:id="browseTextField" editable="false" HBox.hgrow="ALWAYS">
<font>
<Font size="14.0" />
</font>
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</TextField>
<Button fx:id="browseButton" mnemonicParsing="false" onMouseClicked="#browseFiles" text="Browse">
<font>
<Font size="14.0" />
</font>
</Button>
</children>
</HBox>
</content>
<font>
<Font size="14.0" />
</font>
</TitledPane>
</children>
</AnchorPane>
ExternalSpecificationFXController.java 93296c80f8331d5ef5db210c113d6a29f0e2b5e6 GREEN
ExternalSpecificationFXEditor.java f96392509542fa312b9d535dd441644c4c591e2b GREEN
ExternalSpecificationFXEditorBinding.java 642a213c82baee68913c37ccdc0edeef2d3fddf5 GREEN
/*-------------------------------------------------------------------------+
| Copyright 2020 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.af3.cosimulation.ui.editor.fx;
import static java.nio.file.Files.createTempDirectory;
import static org.apache.commons.io.FileUtils.deleteDirectory;
import static org.apache.commons.io.FilenameUtils.removeExtension;
import static org.conqat.ide.commons.ui.dialog.MessageUtils.showError;
import static org.conqat.lib.commons.filesystem.FileSystemUtils.copyFile;
import static org.fortiss.af3.component.utils.ComponentModelElementFactory.createInputPort;
import static org.fortiss.af3.component.utils.ComponentModelElementFactory.createOutputPort;
import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.boolType;
import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.createNoVal;
import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.doubleType;
import static org.fortiss.af3.expression.utils.ExpressionModelElementFactory.intType;
import static org.fortiss.af3.project.utils.FileUtils.getAF3EclipseProject;
import static org.fortiss.af3.project.utils.ProjectUtils.getFileProject;
import static org.fortiss.tooling.kernel.utils.UniqueIDUtils.generateAllIDs;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.core.resources.IResource;
import org.fortiss.af3.component.model.Component;
import org.fortiss.af3.component.model.IReadOnlyBehaviorSpecification;
import org.fortiss.af3.component.model.InputPort;
import org.fortiss.af3.component.model.Port;
import org.fortiss.af3.cosimulation.model.FMUSpecification;
import org.fortiss.af3.cosimulation.model.IExternalBehaviorSpecification;
import org.fortiss.af3.cosimulation.model.SimulinkSpecification;
import org.fortiss.af3.project.model.typesystem.IType;
import org.fortiss.tooling.common.ui.javafx.layout.CompositeFXControllerBase;
import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
import org.fortiss.tooling.kernel.service.IPersistencyService;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
/**
* {@link CompositeFXControllerBase} which allows the user to browse for an
* {@link IExternalBehaviorSpecification}.
*
* @author munaro
*/
// TODO (3926): Complete re-implementation of the cosimulation logic required
@SuppressWarnings("unchecked")
public class ExternalSpecificationFXController extends CompositeFXControllerBase<AnchorPane, Node> {
/**
* {@link IReadOnlyBehaviorSpecification} to specify using an
* {@link IExternalBehaviorSpecification}.
*/
private IReadOnlyBehaviorSpecification behaviorSpecification;
/**
* Sub-folder where all referenced FMUs are stored, relative to the general af3 project
* directory.
*/
public static final String SUBFOLDER = "FMUs";
/**
* {@link Button} opening a {@link FileChooser} to browse for a
* {@link IExternalBehaviorSpecification}.
*/
@FXML
Button browseButton;
/**
* Read-only {@link TextField} displaying the path to the
* {@link IExternalBehaviorSpecification}.
*/
@FXML
TextField browseTextField;
/** {@inheritDoc} */
@Override
public String getFXMLLocation() {
return "ExternalSpecificationEditorLayout.fxml";
}
/** Constructor. */
public ExternalSpecificationFXController(IReadOnlyBehaviorSpecification behaviorSpecification) {
super();
this.behaviorSpecification = behaviorSpecification;
}
/** {@inheritDoc} */
@Override
public void initialize() {
String filePath = null;
if(behaviorSpecification instanceof FMUSpecification) {
filePath = ((FMUSpecification)behaviorSpecification).getFMUPath();
} else {
filePath = ((SimulinkSpecification)behaviorSpecification).getSimPath();
}
browseTextField.setText(filePath);
}
/** Opens a {@link FileChooser} to browse for a {@link FMUSpecification}. */
public void browseFiles() {
executeFileExtractionAndCreateIOPorts(behaviorSpecification,
behaviorSpecification instanceof FMUSpecification);
}
/**
* Unzip the .fmu/.slx and extract the XML file in the temporary build directory. Then, read the
* extracted file to generate the I/O ports for component.
*/
private void executeFileExtractionAndCreateIOPorts(IReadOnlyBehaviorSpecification elt,
boolean isFMU) {
ArrayList<Port> newOutputPorts = new ArrayList<>();
ArrayList<Port> newInputPorts = new ArrayList<>();
ITopLevelElement modelContext =
IPersistencyService.getInstance().getTopLevelElementFor(elt);
modelContext.runAsCommand(() -> {
String filePath;
Component container = null;
String xmlName = null;
ExtensionFilter extensionFilter;
if(isFMU) {
extensionFilter = new ExtensionFilter("FMU specifications (*.fmu)", "*.fmu");
} else {
extensionFilter = new ExtensionFilter("Simulink specifications (*.slx)", "*.slx");
}
filePath = fileDialog(extensionFilter);
if(filePath == null) {
return;
}
filePath = copyExternalSpecificationToAF3ProjectDirectory(filePath);
browseTextField.setText(filePath);
if(isFMU) {
((FMUSpecification)elt).setFMUPath(filePath);
xmlName = "modelDescription.xml";
container = ((FMUSpecification)elt).getComponent();
} else {
((SimulinkSpecification)elt).setSimPath(filePath);
xmlName = "graphicalInterface.xml";
container = ((SimulinkSpecification)elt).getComponent();
}
String tempBuildDirectoryPath = null;
try {
tempBuildDirectoryPath =
createTempDirectory("temporaryXMLFileDirectory").toString();
extractXMLFile(tempBuildDirectoryPath, filePath, xmlName);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser;
saxParser = factory.newSAXParser();
DefaultHandler handler =
parseXMLAndCreateOrModifyPorts(container, newOutputPorts, newInputPorts);
saxParser.parse(tempBuildDirectoryPath + File.separator + xmlName, handler);
generateAllIDs(getFileProject(container));
deleteExtraPorts(newInputPorts, newOutputPorts, container);
} catch(Exception e) {
showError(
"[" + extensionFilter.getExtensions().get(0) +
" Error]: Problem loading the external behavior specification",
"Detailed Error: \n" + e.getMessage());
}
try {
deleteDirectory(new File(tempBuildDirectoryPath));
container.setName(removeExtension(new File(filePath).getName()));
} catch(Exception e) {
showError("[Error]", "Detailed Error: \n" + e.getMessage());
}
});
}
/** Copy the provided {@link IExternalBehaviorSpecification} to the AF3 Directory */
private String copyExternalSpecificationToAF3ProjectDirectory(String filePath) {
File sourceFile = new File(filePath);
IResource targetFolder = getAF3EclipseProject();
File baseFolder = new File(targetFolder.getLocation().toString(), SUBFOLDER);
if(!baseFolder.exists()) {
baseFolder.mkdirs();
}
File targetFile = new File(baseFolder, sourceFile.getName());
try {
if(!targetFile.toString().equals(sourceFile.toString()))
copyFile(sourceFile, targetFile);
} catch(IOException e) {
showError("Copy error", "The file could not be copied into the project directory.");
}
return targetFile.toString();
}
/** Unzip and extract xml file */
private void extractXMLFile(String xmlDestinationDirectory, String zipPath, String xmlName)
throws IOException {
String xmlPath = xmlDestinationDirectory + File.separator + xmlName;
try(ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipPath))) {
ZipEntry entry = zipIn.getNextEntry();
while(entry != null) {
if(!entry.isDirectory() && entry.getName().contains(xmlName)) {
extractFile(zipIn, xmlPath);
}
zipIn.closeEntry();
entry = zipIn.getNextEntry();
}
}
}
/** Extract XML file in the temporary build directory. */
private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
try(BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {
byte[] bytesIn = new byte[4096];
int read = 0;
while((read = zipIn.read(bytesIn)) != -1) {
bos.write(bytesIn, 0, read);
}
}
}
/** Parse XML and create or modify ports. */
private DefaultHandler parseXMLAndCreateOrModifyPorts(Component container,
ArrayList<Port> newOutputPorts, ArrayList<Port> newInputPorts) {
DefaultHandler handler = new DefaultHandler() {
String portName;
boolean isInput = false;
boolean isPort = false;
boolean isParameter = true;
IType type = null;
@Override
public void startElement(String uri, String localName, String startElementName,
Attributes attributes) {
if(startElementName.equals("Inport")) {
portName = attributes.getValue("Name");
isInput = true;
isPort = true;
type = doubleType();
}
if(startElementName.equals("Outport")) {
portName = attributes.getValue("Name");
isInput = false;
isPort = true;
type = doubleType();
}
if(startElementName.equals("ScalarVariable")) {
portName = attributes.getValue("name");
isInput = attributes.getValue("causality").equals("input");
isParameter = !(attributes.getValue("causality").equals("input") ||
attributes.getValue("causality").equals("output"));
}
if(startElementName.equals("Real")) {
type = doubleType();
isPort = true;
}
if(startElementName.equals("Integer")) {
type = intType();
isPort = true;
}
if(startElementName.equals("Boolean")) {
type = boolType();
isPort = true;
}
}
@Override
public void characters(char ch[], int start, int length) {
Port port = null;
if(isPort && !isParameter) {
Port existingPort = isInput ? container.findInputPort(portName)
: container.findOutputPort(portName);
if(existingPort != null) {
existingPort.getPortSpecification().setType(type);
newInputPorts.add(isInput ? existingPort : null);
newOutputPorts.add(isInput ? null : existingPort);
} else if(isInput) {
port = createInputPort(portName, "", type, createNoVal());
container.getConnectors().add(port);
newInputPorts.add(port);
} else {
port = createOutputPort(portName, "", type, createNoVal());
container.getConnectors().add(port);
newOutputPorts.add(port);
}
isPort = false;
isParameter = true;
}
}
};
return handler;
}
/** Open the file dialog and ask to provide the path for the file. */
private String fileDialog(ExtensionFilter extensionFilter) {
FileChooser fileChooser = new FileChooser();
fileChooser.getExtensionFilters().add(extensionFilter);
File file = fileChooser.showOpenDialog(getLayout().getScene().getWindow());
if(file == null) {
return null;
}
return file.getAbsolutePath();
}
/** Delete extra input and output ports. */
private void deleteExtraPorts(ArrayList<Port> newInputPorts, ArrayList<Port> newOutputPorts,
Component container) {
ArrayList<Port> ports = new ArrayList<>(container.getInputPorts());
ports.addAll(container.getOutputPorts());
for(Port p : ports) {
if(p instanceof InputPort ? !newInputPorts.contains(p) : !newOutputPorts.contains(p)) {
container.getConnectors().remove(p);
}
}
}
}
/*-------------------------------------------------------------------------+
| Copyright 2011 fortiss GmbH |
| Copyright 2020 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -13,43 +13,27 @@
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.af3.mira.relation;
package org.fortiss.af3.cosimulation.ui.editor.fx;
import java.util.List;
import org.fortiss.af3.component.model.IReadOnlyBehaviorSpecification;
import org.fortiss.af3.cosimulation.model.IExternalBehaviorSpecification;
import org.fortiss.tooling.kernel.ui.extension.base.FXEditorBase;
import org.eclipse.emf.ecore.EObject;
import org.fortiss.af3.mira.model.relations.RequirementRelationType;
import javafx.scene.Parent;
/**
* AF3 service managing access to registered requirements relations. The
* extension point of the service is {@link org.fortiss.af3.mira.relation}
* Implementation of the {@link IExternalBehaviorSpecification} editor.
*
* @author mou
* @author munaro
*/
public interface IRelationTypeService {
/**
* Singleton instance of the service.
*
* @deprecated use {@link #getInstance()}
*/
@Deprecated
public static final IRelationTypeService INSTANCE = new RelationTypeService();
/** Returns the singleton instance of the service. */
public static IRelationTypeService getInstance() {
return INSTANCE;
public class ExternalSpecificationFXEditor extends FXEditorBase<IReadOnlyBehaviorSpecification> {
/** {@inheritDoc} */
@Override
protected Parent createSceneRoot() {
ExternalSpecificationFXController controller =
new ExternalSpecificationFXController(getEditedObject());
controller.loadLayout();
return controller.getLayout();
}
/** Finds type system handler for the model element's project configuration. */
IRelationTypeHandler<RequirementRelationType> getHandler(EObject element);
/**
* Return a list of all registered handlers. The list can be modified by the
* caller.
*/
List<IRelationTypeHandler<RequirementRelationType>> getHandlers();
/** Return the number of registered handlers. */
int getHandlerCount();
}
/*-------------------------------------------------------------------------+
| Copyright 2013 fortiss GmbH |
| Copyright 2020 fortiss GmbH |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
......@@ -13,33 +13,36 @@
| See the License for the specific language governing permissions and |
| limitations under the License. |
+--------------------------------------------------------------------------*/
package org.fortiss.af3.mira.ui.handler;
package org.fortiss.af3.cosimulation.ui.editor.fx;
import static org.eclipse.ui.plugin.AbstractUIPlugin.imageDescriptorFromPlugin;
import static org.fortiss.af3.mira.ui.AF3MiraUIActivator.PLUGIN_ID;
import org.eclipse.jface.resource.ImageDescriptor;
import org.fortiss.af3.mira.model.relations.RequirementRelationStatus;
import org.fortiss.tooling.kernel.ui.extension.IModelElementHandler;
import org.fortiss.tooling.kernel.ui.extension.base.ModelElementHandlerBase;
import org.eclipse.ui.IEditorPart;
import org.fortiss.af3.cosimulation.model.IExternalBehaviorSpecification;
import org.fortiss.af3.expression.model.DataDictionary;
import org.fortiss.tooling.kernel.ui.extension.base.ModelEditorBindingBase;
/**
* {@link IModelElementHandler} for {@link RequirementRelationStatus}
* Extension of {@link ModelEditorBindingBase} implementation for the
* {@link IExternalBehaviorSpecification} editor.
*
* @author wenwenchen
* @author munaro
*/
public class RequirementRelationStatusHandler
extends ModelElementHandlerBase<RequirementRelationStatus> {
public class ExternalSpecificationFXEditorBinding extends ModelEditorBindingBase<DataDictionary> {
/** {@inheritDoc} */
@Override
public Class<? extends IEditorPart> getEditorClass() {
return ExternalSpecificationFXEditor.class;
}
/** {@inheritDoc} */
@Override
public String getName(RequirementRelationStatus element) {
return element.getName();
public String getLabel() {
return "External Specification Editor (FX)";
}
/** {@inheritDoc} */
@Override
public ImageDescriptor getIconImageDescriptor() {
return imageDescriptorFromPlugin(PLUGIN_ID, "icons/Icon_RequirementRelationStatus.png");
public int getPriority() {
return -100;
}
}
CosimulationPrototypeProvider.java 15a72a81f2e7aaac5352f488bae00fc8d2a3149e GREEN
CosimulationPrototypeProvider.java 6716ca728f39c44a54e3308ef07849e1ab6c62bd GREEN
FMUSpecificationComponentCompositor.java 8ed5aa2c2e567c28b826181cb9696b06e21333de GREEN
SimulinkSpecificationComponentCompositor.java bcc6615de6055cb68f5590694d41d0373b14abde GREEN