blob: f563c80928947d9b5a75ca7aebaf81b1a8446b88 [file] [log] [blame]
/*
* Copyright (c) 2022 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:
* Florian Pauker (TU Wien) pauker@ift.at
* Thomas Fruhwirth (TU Wien) thomas.fruehwirth@tuwien.ac.at
* Saadia Dhouib (CEA LIST) saadia.dhouib@cea.fr
* Fadwa Tmar (CEA LIST) fadwa.tmar@cea.fr
*******************************************************************************/
/*
* This file specifies a QVTo transformation.
*/
import Common.Helpers;
import ClassDiagram.Classes;
import ClassDiagram.Enumerations;
import StateMachineDiagram.StateMachines;
import Uml2Opcua;
//modeltype UA uses 'http://unifiedautomation.com/Configuration/NodeSet.xsd';
modeltype UML uses 'http://www.eclipse.org/uml2/5.0.0/UML';
modeltype SYSML uses 'http://www.eclipse.org/papyrus/sysml/1.6/SysML';
modeltype BLOCKS uses 'http://www.eclipse.org/papyrus/sysml/1.6/SysML/Blocks';
modeltype OPCUA uses set('http://opcfoundation.org/UA/2011/03/UANodeSet.xsd');
modeltype TYPES uses types('http://opcfoundation.org/UA/2008/02/Types.xsd');
modeltype ecore uses 'http://www.eclipse.org/emf/2002/Ecore';
modeltype NodeIdsCsv uses NodeIdsCsv('http://org.eclipse.papyrus.opcua.uml2opcua.nodeIdsCsv.ecore');
modeltype OPCUA_Robotics_Profile uses 'http://Papyrus/OPCUARoboticsProfile';
modeltype OPCUA_Robotics uses opcuarobotics('http://opcfoundation.org/UA/Robotics/');
/*
* UML to OPC UA Model Transformation using QVTo
* @param umlInputModel The UML input model.
* @param opcuaOutputModel The OPC UA output model that will be generated from the umlInputModel by means of model transformation.
*/
//transformation UMLtoOPCUA(in umlInputModel : UML, out opcuaOutputModel : OPCUA, out nodeIdsCsvOutputModel : NodeIdsCsv, in sysml : SYSML, in robotics:OPCUA_Robotics_Profile, in diProfile:OPCUA_DI_Profile, in uaProfile : OPCUA_Profile );
transformation ElementtoOPCUA(in umlElementInputModel : UML, in roboticsProfile:UML, out opcuaOutputModel : OPCUA, out nodeIdsCsvOutputModel : NodeIdsCsv);
property roboticsProfileProfile : UML::Profile = roboticsProfile.rootObjects()![UML::Profile];
//property testMotionDeviceSystemTypeStereotype : UML::Stereotype =roboticsProfileProfile.ownedStereotype![name = "MotionDeviceSystemType"];
/*
* The main entry point of the transformation.
*/
main() {
log("Starting UML 2 OPC UA transformation using QVTo");
// initilize internal datastructures
addNamespace(0, OPCUA_NAMESPACE_URI); // this Namespace Uri always needs to be added
// Namespace Uri DI and Robotics are added only if the robotics profile is applied
if(roboticsProfileProfile!=null) {
addNamespace(1, OPCUA_DI_NAMESPACE_URI);
addNamespace(2, OPCUA_ROBOTICS_NAMESPACE_URI);
} ;
// the transformation supports the use of NodeId aliases, i.e. using human-readable names instead of NodeIds
// these aliases can either be read from a NodeId CSV file, or aliases internally defined in Helpers.qvto
if(CFG_USE_BLACKBOX) {
loadExternalNodeIds(OPCUA_NAMESPACE_URI, "/NodeIds/NS0/NodeIds.csv");
} else {
loadInternalNodeIds();
};
// create a OPCUA::DocumentRoot as the top-level element of the OPC UA model
var documentRoot := object OPCUA::DocumentRoot{};
// map the sleceted UML::Element to OPCUA::NodeSetType elements and collect them in a set
// do same if the selected element is an UML::Model inputModel contains multiple UML::Model elements
var x := documentRoot.xMLNSPrefixMap;
if (umlElementInputModel.rootObjects()![UML::Model]<>null){
documentRoot.uANodeSet += umlElementInputModel.rootObjects()![UML::Model]->map model2OPCUANodeSetType();
}endif;
if (umlElementInputModel.rootObjects()![UML::Element]<>null){
documentRoot.uANodeSet += umlElementInputModel.rootObjects()![UML::Element]->map element2OPCUANodeSetType();
}endif;
}
/*
* Transformation rule mapping a UML::Model element to an OPCUA::UANodeSetType element
*/
mapping UML::Element::element2OPCUANodeSetType() : OPCUA::UANodeSetType {
//add UaModeler Extention
//var uaModelerExtension :=object OPCUA::ExtensionType{};
//extensions:=object ListOfExtensions{extension+=uaModelerExtension};
self->selectByType(UML::Package).package2Namespace(result);
self->selectByType(UML::Model).package2Namespace(result);
// map UML::Classes with stéréotypes : if there is a stereotype that's mean that
//the type is allaready defined in on of the extentions of OPC UA (exple DI or Robitcs)
uAObject += self->selectByType(UML::Class)->select(c|c.getAppliedStereotypes()->exists(s|s.name='MotionDeviceSystemType'))-> map class2MotionDeviceSystemObject(result);
// map UML::Classes without stéréotypes
// map UML::Classes to OPCUA::UAObjectTypes that are not included in any namspeace
// TODO the condition here is to verify if there is no applied stereotypes comming from robotics or another profile
uAObjectType += self->selectByType(UML::Class)->select(c|c.getAppliedStereotypes()->size()=1 and c.getAppliedStereotypes()->exists(s|s.name='Block'))->map class2OPCUAObjectType(result);
// map UML::InstanceSpecification to OPCUA::UAObject that are not included in any namspeace
uAObject += self->selectByType(UML::InstanceSpecification)->map instanceSpecification2OPCUAObject(result);
// map UML::StateMachines to OPCUA::UAObjectTypes that are not included in any namspeace
uAObjectType += self->selectByType(UML::StateMachine)->map statemachine2FiniteStateMachineType(result);
//map UML::Enumerations to OPCUA::UADataType
uADataType+=self->selectByType(UML::Enumeration)->map enumeration2OPCUADataType(result);
// although UML::Associations are top-level elements in a model, UML::Association to OPCUA::Reference transformation is handled as part of the class transformation
// create a OPCUA::UriTable and link it to the DocumentRoot
namespaceUris := object OPCUA::UriTable{};
fillUriTable(namespaceUris);
//TODO add model element of type ModelTableEntry for each profile
//models
if(roboticsProfileProfile!=null) {
//Add the model table entry and the required model entry Di and Robotics
var newModel :=object OPCUA ::ModelTableEntry{};
fillModelTableEntry(newModel,self.getUri());
//TODO add URI for each applied profile
models :=object OPCUA::ModelTable{model+=newModel};
} ;
// create an OPCUA::Alias table
if(CFG_ENABLE_ALIAS_TABLE) {
aliases := object OPCUA::AliasTable{};
fillAliasTable(aliases);
};
// create NodeIdCsv
var nodeIdsCsvFile := object NodeIdsCsv::NodeIdsCsvFile{};
result.createNodeIdsCsv(nodeIdsCsvFile);
}