| /***************************************************************************** |
| * Copyright (c) 2020 CEA LIST. |
| * |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Saadia Dhouib (CEA LIST) saadia.dhouib@cea.fr - Initial API and implementation |
| * |
| *****************************************************************************/ |
| package org.eclipse.papyrus.aas.codegen.ui.handlers; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| |
| import org.apache.maven.model.Model; |
| import org.eclipse.aas.basyx.codegen.util.Project; |
| import org.eclipse.aas.basyx.codegen.util.submodel.SubModel; |
| import org.eclipse.aas.basyx.codegen.util.submodel.SubModelCreator; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IProjectDescription; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.dialogs.ProgressMonitorDialog; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.m2e.core.MavenPlugin; |
| import org.eclipse.m2e.core.project.IProjectConfigurationManager; |
| import org.eclipse.m2e.core.project.MavenProjectInfo; |
| import org.eclipse.m2e.core.project.ProjectImportConfiguration; |
| import org.eclipse.papyrus.aas.Asset; |
| import org.eclipse.papyrus.aas.AssetAdministrationShell; |
| import org.eclipse.papyrus.aas.Submodel; |
| import org.eclipse.papyrus.aas.impl.AssetAdministrationShellImpl; |
| import org.eclipse.papyrus.uml.diagram.common.handlers.CmdHandler; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.uml2.uml.Class; |
| import org.eclipse.uml2.uml.Operation; |
| import org.eclipse.uml2.uml.ParameterDirectionKind; |
| import org.eclipse.uml2.uml.Property; |
| import org.eclipse.uml2.uml.Stereotype; |
| import org.eclipse.uml2.uml.util.UMLUtil; |
| import org.osgi.framework.Bundle; |
| |
| public class GenerateAASCodeHandler extends CmdHandler { |
| |
| @Override |
| public Object execute(ExecutionEvent event) throws ExecutionException { |
| updateSelectedEObject(); |
| |
| IRunnableWithProgress op = new IRunnableWithProgress() { |
| |
| @Override |
| public void run(IProgressMonitor monitor) { |
| monitor.beginTask("Generating Basyx Code...", IProgressMonitor.UNKNOWN); |
| try { |
| executeCodeGen(monitor); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| monitor.done(); |
| } |
| }; |
| try { |
| new ProgressMonitorDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()).run(true, true, |
| op); |
| MessageDialog.openInformation(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Success", |
| "The project " + ((Class) selectedEObject).getName() |
| + " has been successfully generated and imported into your workspace"); |
| |
| } catch (InvocationTargetException e) { |
| |
| e.printStackTrace(); |
| MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error", |
| e.toString()); |
| |
| } catch (InterruptedException e) { |
| |
| e.printStackTrace(); |
| MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error", |
| e.toString()); |
| |
| } catch (Exception e) { |
| e.printStackTrace(); |
| MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error", |
| e.toString()); |
| |
| } |
| |
| return null; |
| } |
| |
| private Object executeCodeGen(IProgressMonitor monitor) { |
| Class selectedClass = (Class) selectedEObject; |
| AssetAdministrationShell aas = UMLUtil.getStereotypeApplication(selectedClass, AssetAdministrationShell.class); |
| if (aas != null) { |
| |
| URI uri = selectedClass.eResource().getURI(); |
| |
| IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); |
| if (uri.segmentCount() < 2) { |
| return null; |
| } |
| String projectLocation = uri.segment(1); |
| try { |
| projectLocation = URLDecoder.decode(uri.segment(1), "UTF-8"); |
| } catch (UnsupportedEncodingException e1) { |
| // TODO Auto-generated catch block |
| e1.printStackTrace(); |
| } |
| // System.err.println("projectLocation "+ projectLocation); |
| IProject modelProject = root.getProject(projectLocation); |
| if (modelProject.exists()) { |
| // TODO Auto-generated method stub |
| // Set project settings |
| // Create project files |
| |
| // List of the submodels from papyrus model |
| List<Submodel> submodels = new ArrayList<>(); |
| // List of submodels for basyx code generator |
| List<SubModel> basyx_submodels = new ArrayList<>(); |
| // get submodels of the AAS, their operations and their properties |
| submodels = aas.getSubmodel(); |
| for (int i = 0; i < submodels.size(); i++) { |
| Submodel submodel = submodels.get(i); |
| Class submodelClass = submodel.getBase_Class(); |
| if (submodelClass != null) { |
| String submodelName = submodelClass.getName(); |
| SubModel basyxSubmodel = new SubModel(submodelName); |
| |
| // add submodel operations |
| if (submodelClass.getAllOperations() != null && submodelClass.getAllOperations().size() > 0) { |
| for (int j = 0; j < submodelClass.getAllOperations().size(); j++) { |
| Operation op = submodelClass.getAllOperations().get(j); |
| String opName = op.getName(); |
| if (opName != null && opName.length() > 0) { |
| basyxSubmodel.addOperation(opName); |
| basyxSubmodel.addInputVariables(opName, |
| getOperationParameters(op, ParameterDirectionKind.IN)); |
| basyxSubmodel.addOutputVariables(opName, |
| getOperationParameters(op, ParameterDirectionKind.OUT)); |
| basyxSubmodel.addInOutputVariables(opName, |
| getOperationParameters(op, ParameterDirectionKind.INOUT)); |
| |
| } else { |
| basyxSubmodel.addOperation("op" + j); |
| } |
| } |
| } |
| |
| // add submodel properties |
| if (submodelClass.getAllAttributes() != null && submodelClass.getAllAttributes().size() > 0) { |
| for (int j = 0; j < submodelClass.getAllAttributes().size(); j++) { |
| Property submodelElement = submodelClass.getAllAttributes().get(j); |
| |
| String attName = submodelElement.getName(); |
| |
| // Generate a submodel property if there is no stereotype applied on the |
| // property |
| if ((submodelElement.getAppliedStereotypes() == null) |
| || (submodelElement.getAppliedStereotypes().size() == 0)) { |
| if (submodelElement.getDefaultValue() != null) { |
| |
| String attValue = submodelElement.getDefaultValue().stringValue(); |
| |
| if (attName != null && attName.length() > 0 && attValue != null |
| && attValue.length() > 0) { |
| basyxSubmodel.addProperty(attName, attValue); |
| } |
| } else if (attName != null && attName.length() > 0) { |
| basyxSubmodel.addProperty(attName); |
| } else { |
| basyxSubmodel.addProperty("attribute" + j); |
| } |
| } else { |
| // aad submodel element collection |
| generateSubmodelElementCollection(submodelElement, basyxSubmodel); |
| |
| // add submodel property |
| generateProperty(submodelElement, basyxSubmodel, j); |
| |
| generateFile(submodelElement, basyxSubmodel); |
| |
| } |
| |
| } |
| } |
| basyx_submodels.add(basyxSubmodel); |
| |
| } |
| |
| } |
| |
| SubModelCreator mc = new SubModelCreator(); |
| |
| // Add submodels |
| for (int i = 0; i < basyx_submodels.size(); i++) { |
| mc.addSubModel(basyx_submodels.get(i)); |
| |
| } |
| |
| // get parameters for project creation |
| |
| // aas url |
| |
| String aasUrl = ""; |
| if (((AssetAdministrationShellImpl) aas).getUrl() != null) { |
| aasUrl = ((AssetAdministrationShellImpl) aas).getUrl(); |
| } else { |
| aasUrl = "localhost"; |
| } |
| |
| // aas port |
| |
| String aasPort = ""; |
| if (((AssetAdministrationShellImpl) aas).getPort() > 0) { |
| aasPort = Integer.toString(((AssetAdministrationShellImpl) aas).getPort()); |
| } else { |
| aasPort = "5125"; |
| } |
| |
| // aas id |
| |
| String aasId = "urn:de.basyfloor:devices:DeviceAAS:1.0:1:floordevice#001"; |
| if (((AssetAdministrationShellImpl) aas).getIdentification() != null |
| && ((AssetAdministrationShellImpl) aas).getIdentification().getId() != null) { |
| aasId = ((AssetAdministrationShellImpl) aas).getIdentification().getId(); |
| } |
| |
| // asset address |
| String deviceEndpoint = "opc.tcp://192.168.0.37:4840"; |
| |
| if (((AssetAdministrationShellImpl) aas).getAsset() != null) { |
| Asset asset = ((AssetAdministrationShellImpl) aas).getAsset(); |
| if (asset.getEndpoint() != null && asset.getEndpoint().size() > 0) { |
| if (asset.getEndpoint().get(0) != null) { |
| if (asset.getEndpoint().get(0).getAddress() != null) { |
| deviceEndpoint = asset.getEndpoint().get(0).getAddress().toString(); |
| } |
| } |
| } |
| |
| } |
| |
| // Create project files |
| // Project aasproject = new |
| // Project("urn:de.basyfloor:devices:DeviceAAS:1.0:1:floordevice#001", |
| // aasUrl, aasPort, mc, "opc.tcp://192.168.0.37:4840"); |
| Project aasproject = new Project(aasId, aasUrl, aasPort, mc, deviceEndpoint); |
| // Currently only OPC-UA connection with the devices are possible |
| |
| // If below is commented out, it creates project files in the working folder. |
| aasproject.setProjectName(selectedClass.getName()); // The asset name as well as the project name |
| aasproject.setNamespaceFromProjectName(); // Creates project structure in Eclipse automatically based on |
| // project name |
| // testAAS.setNamespace("eu.dfki.canvaas.project"); // Instead, it is possible |
| // to use explicit namespacing. |
| aasproject.setProjectFolder(root.getLocation().toString() + "/" + selectedClass.getName() + "/"); |
| |
| Bundle bundle = Platform.getBundle("org.eclipse.aas.basyx.codegen"); |
| |
| if (bundle != null) { |
| final URL extLibEclipseURL = FileLocator.find(bundle, new Path("/extClasses"), null); |
| |
| String extLibURL = null; |
| try { |
| URL fileURL = FileLocator.toFileURL(extLibEclipseURL); |
| if (fileURL != null) { |
| extLibURL = fileURL.toString(); |
| if (extLibURL != null) |
| { |
| extLibURL = extLibURL.replaceAll("file:/", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| System.err.println("CanvAAS full path : " + extLibURL); |
| |
| aasproject.setExternalClassFolder("/" + extLibURL); |
| |
| } |
| aasproject.linkAAS(aasproject); |
| |
| // Create the runnable project |
| aasproject.createProject(); |
| |
| // Import and open the project in the workspace |
| |
| IProjectDescription description; |
| try { |
| |
| description = ResourcesPlugin.getWorkspace().loadProjectDescription( |
| new Path(root.getLocation().toString() + "/" + selectedClass.getName() + "/.project")); |
| |
| File pomFile = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toString() + "/" |
| + selectedClass.getName() + "/pom.xml"); |
| importMavenProjects(monitor, pomFile, description.getName(), "aas", "aasmodule", "0.1"); |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| |
| } |
| } |
| return null; |
| } |
| |
| |
| private LinkedHashMap<String,String> getOperationParameters(Operation op, int direction) { |
| LinkedHashMap<String, String> inParamaters = new LinkedHashMap<String, String>(); |
| if (op.getOwnedParameters() != null) { |
| |
| |
| for (int i = 0; i < op.getOwnedParameters().size(); i++) { |
| if (op.getOwnedParameters().get(i) != null && op.getOwnedParameters().get(i).getName()!=null) { |
| System.err.println("searched direction: " + direction); |
| System.err.println(op.getOwnedParameters().get(i).getName() + " direction: " |
| + op.getOwnedParameters().get(i).getDirection()); |
| |
| if (op.getOwnedParameters().get(i).getDirection().getValue() == direction) { |
| String paramType="String"; |
| System.err.println("found parameter for direction " + direction + "\n"); |
| if(op.getOwnedParameters().get(i).getType()!=null && op.getOwnedParameters().get(i).getType().getName()!=null ) |
| { |
| paramType=op.getOwnedParameters().get(i).getType().getName(); |
| } |
| inParamaters.put(op.getOwnedParameters().get(i).getName(),paramType); |
| } |
| } |
| } |
| |
| } |
| return inParamaters; |
| |
| } |
| |
| private void importMavenProjects(IProgressMonitor monitor, File pomFile, String projectName, String groupId, |
| String artifactId, String version) throws CoreException { |
| |
| IProjectConfigurationManager manager = MavenPlugin.getProjectConfigurationManager(); |
| ProjectImportConfiguration config = new ProjectImportConfiguration(); |
| Collection<MavenProjectInfo> infos = new ArrayList<>(); |
| Model model = new Model(); |
| model.setGroupId(groupId); |
| model.setArtifactId(artifactId); |
| model.setVersion(version); |
| |
| model.setPomFile(pomFile); |
| MavenProjectInfo info = new MavenProjectInfo(projectName, pomFile, model, null); |
| infos.add(info); |
| |
| manager.importProjects(infos, config, monitor); |
| } |
| |
| private void generateSubmodelElementCollection(Property submodelElement, SubModel basyxSubmodel) { |
| if (org.eclipse.papyrus.uml.tools.utils.UMLUtil.getAppliedStereotype(submodelElement, |
| "AAS::SubmodelElementCollection", true) != null) { |
| basyxSubmodel.addSubModelElementCollection(submodelElement.getName()); |
| if ((submodelElement.getType() != null) && (submodelElement.getType() instanceof Class)) { |
| Class collection = (Class) submodelElement.getType(); |
| |
| // generate attributes of the submodelelementcollection |
| for (Property collectionchild : collection.getAllAttributes()) { |
| // case of addSubModelElementCollection subelement is a Property |
| if (org.eclipse.papyrus.uml.tools.utils.UMLUtil.getAppliedStereotype(collectionchild, |
| "AAS::Property", true) != null) { |
| |
| basyxSubmodel.addPropertyToSubModelElementCollection(collectionchild.getName(), |
| submodelElement.getName()); |
| } |
| |
| // case of addSubModelElementCollection subelement is a File |
| Stereotype stFile = org.eclipse.papyrus.uml.tools.utils.UMLUtil |
| .getAppliedStereotype(collectionchild, "AAS::File", true); |
| if (stFile != null) { |
| |
| Object valueObject = collectionchild.getValue(stFile, "path"); |
| if (valueObject != null) { |
| basyxSubmodel.addFilePath(valueObject.toString(), submodelElement.getName()); |
| } else { |
| basyxSubmodel.addFilePath(collectionchild.getName(), submodelElement.getName()); |
| } |
| |
| } |
| |
| // case of addSubModelElementCollection subelement is a |
| // SubModelElementCollection |
| Stereotype stCollection = org.eclipse.papyrus.uml.tools.utils.UMLUtil |
| .getAppliedStereotype(collectionchild, "AAS::SubmodelElementCollection", true); |
| if (stCollection != null) { |
| |
| // waiting for the basyx API to support this case |
| // |
| } |
| |
| } |
| |
| // generate operations of the submodelelementcollection |
| for (Operation collectionchildop : collection.getAllOperations()) { |
| if (collectionchildop != null) { |
| String opName = "op"; |
| if (collectionchildop.getName() != null && collectionchildop.getName().isEmpty() != true) { |
| opName = collectionchildop.getName(); |
| } |
| |
| basyxSubmodel.addOperationToSubModelElementCollection(opName, submodelElement.getName()); |
| |
| basyxSubmodel.addInputVariables(opName, |
| getOperationParameters(collectionchildop, ParameterDirectionKind.IN)); |
| basyxSubmodel.addOutputVariables(opName, |
| getOperationParameters(collectionchildop, ParameterDirectionKind.OUT)); |
| basyxSubmodel.addInOutputVariables(opName, |
| getOperationParameters(collectionchildop, ParameterDirectionKind.INOUT)); |
| // basyxSubmodel.addInputVariables(opName, null); |
| // basyxSubmodel.addOutputVariables(opName, null); |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| private void generateProperty(Property submodelElement, SubModel basyxSubmodel, int j) { |
| // TODO Auto-generated method stub |
| if (org.eclipse.papyrus.uml.tools.utils.UMLUtil.getAppliedStereotype(submodelElement, "AAS::Property", |
| true) != null) { |
| String attName = submodelElement.getName(); |
| if (submodelElement.getDefaultValue() != null) { |
| |
| String attValue = submodelElement.getDefaultValue().stringValue(); |
| if (attName != null && submodelElement.getType() != null |
| && submodelElement.getType().getName() != null) { |
| if (attValue == null) { |
| basyxSubmodel.addProperty(attName, "undefined", submodelElement.getType().getName()); |
| } else { |
| basyxSubmodel.addProperty(attName, attValue, submodelElement.getType().getName()); |
| } |
| } |
| if (attName != null && attName.length() > 0 && attValue != null && attValue.length() > 0) { |
| basyxSubmodel.addProperty(attName, attValue); |
| } |
| } else if (attName != null && attName.length() > 0) { |
| basyxSubmodel.addProperty(attName); |
| } else { |
| basyxSubmodel.addProperty("attribute" + j); |
| } |
| } |
| |
| } |
| |
| private void generateFile(Property submodelElement, SubModel basyxSubmodel) { |
| // TODO Auto-generated method stub |
| Stereotype stFile = org.eclipse.papyrus.uml.tools.utils.UMLUtil.getAppliedStereotype(submodelElement, |
| "AAS::File", true); |
| if (stFile != null) { |
| |
| Object valueObject = submodelElement.getValue(stFile, "path"); |
| if (valueObject != null) { |
| basyxSubmodel.addFilePath(valueObject.toString()); |
| } else { |
| basyxSubmodel.addFilePath(submodelElement.getName()); |
| } |
| |
| } |
| |
| } |
| |
| } |