Skip to content

Commit

Permalink
Added support for slots in UML instance specifications
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasfruehwirth committed Dec 2, 2020
1 parent 27a075d commit 1418a92
Show file tree
Hide file tree
Showing 7 changed files with 339 additions and 21 deletions.
116 changes: 114 additions & 2 deletions QvtoTransformationRules/transforms/ClassDiagram/Instances.qvto
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,124 @@ import Common.Helpers;

modeltype UML uses 'http://www.eclipse.org/uml2/5.0.0/UML';
modeltype OPCUA uses set('http://opcfoundation.org/UA/2011/03/UANodeSet.xsd');
modeltype ECORE uses ecore('http://www.eclipse.org/emf/2002/Ecore');
modeltype TYPES uses types('http://opcfoundation.org/UA/2008/02/Types.xsd');
modeltype ecore "strict" uses 'http://www.eclipse.org/emf/2002/Ecore';

/*
* Transforms an UML::InstanceSpecification to an OPCUA::UAObject
* In many cases, it would be cumbersome to also add instances for all Properties, Operations, Compositions manually
* Therefore, if not manually specified, the elements defined by the class corresponding to the UML::InstanceSpecification
* will be used to generated the relevant OPC UA objects, variables, etc.
* @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.
*/

mapping UML::InstanceSpecification::instanceSpecification2OPCUAObject(inout nodeset : OPCUA::UANodeSetType) : OPCUA::UAObject {
log("instanceSpecification2OPCUAObject for UML element " + self.name);
// set attributes of the OPCUA::UAObject
browseName := self.createBrowseName();
nodeId := self.createNodeId();
displayName := (object OPCUA::LocalizedText {value := browseName})->asOrderedSet();
}

// transform property slots of the Instance
nodeset.uAVariable += self.ownedElement->selectByType(UML::Slot)->select(slot | slot.definingFeature.oclIsTypeOf(UML::Property))->map transformPropertySlot2UAVariable(result);

// TODO: transform properties of the class that are not defined as slot

assert warning (self.classifier->size() <= 1) with log("Element specifies more than one classifier. Only the first value is used");
_references := object OPCUA::ListOfReferences{};
_references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("HasTypeDefinition"); value := self.classifier->any(true).createNodeId()}; // should only have one classifier
_references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("Organizes"); value := getIdOrAlias("ObjectsFolder"); isForward := false};
}

mapping UML::Slot::transformPropertySlot2UAVariable(inout parent : OPCUA::UANode) : OPCUA::UAVariable {
var definingFeature := self.definingFeature.oclAsType(UML::Property);

// set attributs of the OPCUA::UAVariable
nodeId := self.createNodeId();
browseName := definingFeature.createBrowseName(); // a slot does not have a name, so use the name of its defining feature
displayName := object OPCUA::LocalizedText{value := browseName};

assert warning (self.value->size() <= 1) with log("Element specifies more than one value. Only the first value is used");

// set the datatype and maybe the value of the UA::Variable
if(definingFeature.type.toString().find("Int") > 0) {
dataType := getIdOrAlias("Int32");
var v : UML::LiteralInteger = null;
if(self.value->size() > 0) {
v := self.value->first().oclAsType(UML::LiteralInteger);
} else if(definingFeature.defaultValue <> null) { // set the value to the difininigFeature.defaultValue if specified
v := definingFeature.defaultValue.oclAsType(UML::LiteralInteger);
};

if(v <> null) {
var feature := TYPES::DocumentRoot.oclAsType(EClass).getEStructuralFeature("int32");
value := object OPCUA::ValueType1{};
value.oclAsType(EObject).eSet(feature, v.value); // the slot should only have a single value
};
} else if (definingFeature.type.toString().find("String") > 0) {
dataType := getIdOrAlias("String");
var v : UML::LiteralString = null;
if(self.value->size() > 0) {
v := self.value->first().oclAsType(UML::LiteralString);
} else if(definingFeature.defaultValue <> null) { // set the value to the difininigFeature.defaultValue if specified
v := definingFeature.defaultValue.oclAsType(UML::LiteralString);
};

if(v <> null) {
var feature := TYPES::DocumentRoot.oclAsType(EClass).getEStructuralFeature("string");
value := object OPCUA::ValueType1{};
value.oclAsType(EObject).eSet(feature, v.value); // the slot should only have a single value
};
} else if (definingFeature.type.toString().find("Real") > 0 or definingFeature.type.toString().find("Double") > 0 or definingFeature.type.toString().find("Float") > 0) {
dataType := getIdOrAlias("Double");
var v : UML::LiteralReal = null;
if(self.value->size() > 0) {
v := self.value->first().oclAsType(UML::LiteralReal);
} else if(definingFeature.defaultValue <> null) { // set the value to the difininigFeature.defaultValue if specified
v := definingFeature.defaultValue.oclAsType(UML::LiteralReal);
};

if(v <> null) {
var feature := TYPES::DocumentRoot.oclAsType(EClass).getEStructuralFeature("double");
value := object OPCUA::ValueType1{};
value.oclAsType(EObject).eSet(feature, v.value); // the slot should only have a single value
};
} else if (definingFeature.type.toString().find("Boolean") > 0) {
var v : UML::LiteralBoolean = null;
if(self.value->size() > 0) {
v := self.value->first().oclAsType(UML::LiteralBoolean);
} else if(definingFeature.defaultValue <> null) { // set the value to the difininigFeature.defaultValue if specified
v := definingFeature.defaultValue.oclAsType(UML::LiteralBoolean);
};

if(v <> null) {
var feature := TYPES::DocumentRoot.oclAsType(EClass).getEStructuralFeature("boolean");
value := object OPCUA::ValueType1{};
value.oclAsType(EObject).eSet(feature, v.value); // the slot should only have a single value
};
} else {
raise Exception("Unkown datatype for slot of instace declation " + self.owner.oclAsType(UML::InstanceSpecification).name);
};

// link the OPCUA::UAVariable to the parent via a HasComponent reference
parent._references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("HasComponent"); value := nodeId};
parentNodeId := parent.nodeId;

// add references
_references := object OPCUA::ListOfReferences{};
_references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("HasTypeDefinition"); value := getIdOrAlias("BaseDataVariableType")};
_references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("HasModellingRule"); value := getIdOrAlias("ModellingRule_Mandatory")}; // TODO replace with correct modelling rule
_references.reference += object OPCUA::Reference{referenceType := getIdOrAlias("HasComponent"); value := parent.nodeId; isForward := false};

}

/*
helper UML::Slot::transformPropertySlot2UAVariable(inout nodeset: OPCUA::UANodeSetType) : OPCUA::UAVariable{
log("transformPropertySlot for UML element " + self.toString());
// transform slots of the InstanceSpecification, i.e.,
// nodeset.uAVariable += self.ownedElement->selectByType(UML::Property)->select(x|x.association = null and x.type.oclIsKindOf(UML::PrimitiveType))->map property2UAVariable(result)->asOrderedSet(); // variables do not have an association field
var p := self.definingFeature.oclAsType(UML::Property);
log("p: " + p.toString());
}
*/
10 changes: 1 addition & 9 deletions Uml2OpcuaTransformationTests/Instance.notation
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
<layoutConstraint xmi:type="notation:Location" xmi:id="_pvEKosdPEeqBwPQ5-6UCwg" y="15"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_pvN7oMdPEeqBwPQ5-6UCwg" type="Class_AttributeCompartment">
<children xmi:type="notation:Shape" xmi:id="_Q-eSQDPhEeusqo4eorF9lg" type="Property_ClassAttributeLabel">
<element xmi:type="uml:Property" href="Instance.uml#_Q-UhQDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_Q-eSQTPhEeusqo4eorF9lg"/>
</children>
<styles xmi:type="notation:TitleStyle" xmi:id="_pvN7ocdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_pvN7osdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_pvN7o8dPEeqBwPQ5-6UCwg"/>
Expand Down Expand Up @@ -42,17 +38,13 @@
<layoutConstraint xmi:type="notation:Location" xmi:id="_KYTPhDPhEeusqo4eorF9lg" y="15"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_KYTPhTPhEeusqo4eorF9lg" type="InstanceSpecification_SlotCompartment">
<children xmi:type="notation:Shape" xmi:id="_J7uLwDPiEeusqo4eorF9lg" type="Slot_SlotLabel">
<element xmi:type="uml:Slot" href="Instance.uml#_J7neEDPiEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_J7uLwTPiEeusqo4eorF9lg"/>
</children>
<styles xmi:type="notation:TitleStyle" xmi:id="_KYTPhjPhEeusqo4eorF9lg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_KYTPhzPhEeusqo4eorF9lg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_KYTPiDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KYTPiTPhEeusqo4eorF9lg"/>
</children>
<element xmi:type="uml:InstanceSpecification" href="Instance.uml#_KYJegDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KYTPgTPhEeusqo4eorF9lg" x="1020" y="300"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KYTPgTPhEeusqo4eorF9lg" x="920" y="280"/>
</children>
<styles xmi:type="notation:StringValueStyle" xmi:id="_n9rskcdPEeqBwPQ5-6UCwg" name="diagram_compatibility_version" stringValue="1.4.0"/>
<styles xmi:type="notation:DiagramStyle" xmi:id="_n9rsksdPEeqBwPQ5-6UCwg"/>
Expand Down
12 changes: 2 additions & 10 deletions Uml2OpcuaTransformationTests/Instance.uml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@
<packageImport xmi:type="uml:PackageImport" xmi:id="_oCcQwMdPEeqBwPQ5-6UCwg">
<importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
</packageImport>
<packagedElement xmi:type="uml:Class" xmi:id="_punesMdPEeqBwPQ5-6UCwg" name="Class5">
<ownedAttribute xmi:type="uml:Property" xmi:id="_Q-UhQDPhEeusqo4eorF9lg" name="Manufacturer">
<type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/EcorePrimitiveTypes.library.uml#EString"/>
</ownedAttribute>
</packagedElement>
<packagedElement xmi:type="uml:InstanceSpecification" xmi:id="_KYJegDPhEeusqo4eorF9lg" name="Class5Instance" classifier="_punesMdPEeqBwPQ5-6UCwg">
<slot xmi:type="uml:Slot" xmi:id="_J7neEDPiEeusqo4eorF9lg" definingFeature="_Q-UhQDPhEeusqo4eorF9lg">
<value xmi:type="uml:LiteralString" xmi:id="_fLmp4DPiEeusqo4eorF9lg" value="MyManufacturer"/>
</slot>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_punesMdPEeqBwPQ5-6UCwg" name="Class5"/>
<packagedElement xmi:type="uml:InstanceSpecification" xmi:id="_KYJegDPhEeusqo4eorF9lg" name="Class5Instance" classifier="_punesMdPEeqBwPQ5-6UCwg"/>
</uml:Model>
2 changes: 2 additions & 0 deletions Uml2OpcuaTransformationTests/InstanceWithSlots.di
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<architecture:ArchitectureDescription xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:architecture="http://www.eclipse.org/papyrus/infra/core/architecture" contextId="org.eclipse.papyrus.infra.services.edit.TypeContext"/>
87 changes: 87 additions & 0 deletions Uml2OpcuaTransformationTests/InstanceWithSlots.notation
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<notation:Diagram xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:notation="http://www.eclipse.org/gmf/runtime/1.0.3/notation" xmlns:style="http://www.eclipse.org/papyrus/infra/gmfdiag/style" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_n9rskMdPEeqBwPQ5-6UCwg" type="PapyrusUMLClassDiagram" name="Class Diagram" measurementUnit="Pixel">
<children xmi:type="notation:Shape" xmi:id="_pu7AsMdPEeqBwPQ5-6UCwg" type="Class_Shape">
<children xmi:type="notation:DecorationNode" xmi:id="_pvEKoMdPEeqBwPQ5-6UCwg" type="Class_NameLabel">
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
</children>
<children xmi:type="notation:DecorationNode" xmi:id="_pvEKocdPEeqBwPQ5-6UCwg" type="Class_FloatingNameLabel">
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_pvEKosdPEeqBwPQ5-6UCwg" y="15"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_pvN7oMdPEeqBwPQ5-6UCwg" type="Class_AttributeCompartment">
<children xmi:type="notation:Shape" xmi:id="_Q-eSQDPhEeusqo4eorF9lg" type="Property_ClassAttributeLabel">
<element xmi:type="uml:Property" href="InstanceWithSlots.uml#_Q-UhQDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_Q-eSQTPhEeusqo4eorF9lg"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_FfMRoDSIEeuvtL-cjTXdxg" type="Property_ClassAttributeLabel">
<element xmi:type="uml:Property" href="InstanceWithSlots.uml#_FevlsDSIEeuvtL-cjTXdxg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_FfMRoTSIEeuvtL-cjTXdxg"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_RlWLIDSIEeuvtL-cjTXdxg" type="Property_ClassAttributeLabel">
<element xmi:type="uml:Property" href="InstanceWithSlots.uml#_RlIvwDSIEeuvtL-cjTXdxg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_RlWLITSIEeuvtL-cjTXdxg"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_vxpbwDS2EeuvtL-cjTXdxg" type="Property_ClassAttributeLabel">
<element xmi:type="uml:Property" href="InstanceWithSlots.uml#_vxgR0DS2EeuvtL-cjTXdxg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_vxpbwTS2EeuvtL-cjTXdxg"/>
</children>
<styles xmi:type="notation:TitleStyle" xmi:id="_pvN7ocdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_pvN7osdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_pvN7o8dPEeqBwPQ5-6UCwg"/>
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_pvN7pMdPEeqBwPQ5-6UCwg"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_pvN7pcdPEeqBwPQ5-6UCwg" type="Class_OperationCompartment">
<styles xmi:type="notation:TitleStyle" xmi:id="_pvN7psdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_pvN7p8dPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_pvN7qMdPEeqBwPQ5-6UCwg"/>
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_pvN7qcdPEeqBwPQ5-6UCwg"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_pvN7qsdPEeqBwPQ5-6UCwg" type="Class_NestedClassifierCompartment">
<styles xmi:type="notation:TitleStyle" xmi:id="_pvN7q8dPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_pvN7rMdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_pvN7rcdPEeqBwPQ5-6UCwg"/>
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_pvN7rsdPEeqBwPQ5-6UCwg"/>
</children>
<element xmi:type="uml:Class" href="InstanceWithSlots.uml#_punesMdPEeqBwPQ5-6UCwg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_pu7AscdPEeqBwPQ5-6UCwg" x="160" y="80"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_KYTPgDPhEeusqo4eorF9lg" type="InstanceSpecification_Shape">
<children xmi:type="notation:DecorationNode" xmi:id="_KYTPgjPhEeusqo4eorF9lg" type="InstanceSpecification_NameLabel">
<element xmi:type="uml:InstanceSpecification" href="InstanceWithSlots.uml#_KYJegDPhEeusqo4eorF9lg"/>
</children>
<children xmi:type="notation:DecorationNode" xmi:id="_KYTPgzPhEeusqo4eorF9lg" type="InstanceSpecification_FloatingNameLabel">
<element xmi:type="uml:InstanceSpecification" href="InstanceWithSlots.uml#_KYJegDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_KYTPhDPhEeusqo4eorF9lg" y="15"/>
</children>
<children xmi:type="notation:BasicCompartment" xmi:id="_KYTPhTPhEeusqo4eorF9lg" type="InstanceSpecification_SlotCompartment">
<children xmi:type="notation:Shape" xmi:id="_J7uLwDPiEeusqo4eorF9lg" type="Slot_SlotLabel">
<element xmi:type="uml:Slot" href="InstanceWithSlots.uml#_J7neEDPiEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_J7uLwTPiEeusqo4eorF9lg"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_XqwqMDSIEeuvtL-cjTXdxg" type="Slot_SlotLabel">
<element xmi:type="uml:Slot" href="InstanceWithSlots.uml#_XqlEADSIEeuvtL-cjTXdxg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_XqwqMTSIEeuvtL-cjTXdxg"/>
</children>
<children xmi:type="notation:Shape" xmi:id="_8IljQDS2EeuvtL-cjTXdxg" type="Slot_SlotLabel">
<element xmi:type="uml:Slot" href="InstanceWithSlots.uml#_8IbyQDS2EeuvtL-cjTXdxg"/>
<layoutConstraint xmi:type="notation:Location" xmi:id="_8IljQTS2EeuvtL-cjTXdxg"/>
</children>
<styles xmi:type="notation:TitleStyle" xmi:id="_KYTPhjPhEeusqo4eorF9lg"/>
<styles xmi:type="notation:SortingStyle" xmi:id="_KYTPhzPhEeusqo4eorF9lg"/>
<styles xmi:type="notation:FilteringStyle" xmi:id="_KYTPiDPhEeusqo4eorF9lg"/>
<element xmi:type="uml:InstanceSpecification" href="InstanceWithSlots.uml#_KYJegDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KYTPiTPhEeusqo4eorF9lg"/>
</children>
<element xmi:type="uml:InstanceSpecification" href="InstanceWithSlots.uml#_KYJegDPhEeusqo4eorF9lg"/>
<layoutConstraint xmi:type="notation:Bounds" xmi:id="_KYTPgTPhEeusqo4eorF9lg" x="460" y="80"/>
</children>
<styles xmi:type="notation:StringValueStyle" xmi:id="_n9rskcdPEeqBwPQ5-6UCwg" name="diagram_compatibility_version" stringValue="1.4.0"/>
<styles xmi:type="notation:DiagramStyle" xmi:id="_n9rsksdPEeqBwPQ5-6UCwg"/>
<styles xmi:type="style:PapyrusDiagramStyle" xmi:id="_n9rsk8dPEeqBwPQ5-6UCwg" diagramKindId="org.eclipse.papyrus.uml.diagram.class">
<owner xmi:type="uml:Model" href="InstanceWithSlots.uml#_n7J9AMdPEeqBwPQ5-6UCwg"/>
</styles>
<element xmi:type="uml:Model" href="InstanceWithSlots.uml#_n7J9AMdPEeqBwPQ5-6UCwg"/>
</notation:Diagram>
Loading

0 comments on commit 1418a92

Please sign in to comment.