diff --git a/QvtoTransformationRules/transforms/ClassDiagram/Instances.qvto b/QvtoTransformationRules/transforms/ClassDiagram/Instances.qvto
index 475c8e5..dcc1fc1 100644
--- a/QvtoTransformationRules/transforms/ClassDiagram/Instances.qvto
+++ b/QvtoTransformationRules/transforms/ClassDiagram/Instances.qvto
@@ -4,7 +4,17 @@ 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);
@@ -12,4 +22,106 @@ mapping UML::InstanceSpecification::instanceSpecification2OPCUAObject(inout node
browseName := self.createBrowseName();
nodeId := self.createNodeId();
displayName := (object OPCUA::LocalizedText {value := browseName})->asOrderedSet();
-}
\ No newline at end of file
+
+ // 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());
+}
+*/
\ No newline at end of file
diff --git a/Uml2OpcuaTransformationTests/Instance.notation b/Uml2OpcuaTransformationTests/Instance.notation
index e77a3ed..ad45fa1 100644
--- a/Uml2OpcuaTransformationTests/Instance.notation
+++ b/Uml2OpcuaTransformationTests/Instance.notation
@@ -9,10 +9,6 @@
-
-
-
-
@@ -42,17 +38,13 @@
-
-
-
-
-
+
diff --git a/Uml2OpcuaTransformationTests/Instance.uml b/Uml2OpcuaTransformationTests/Instance.uml
index 7fd50d5..626ba6d 100644
--- a/Uml2OpcuaTransformationTests/Instance.uml
+++ b/Uml2OpcuaTransformationTests/Instance.uml
@@ -3,14 +3,6 @@
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/Uml2OpcuaTransformationTests/InstanceWithSlots.di b/Uml2OpcuaTransformationTests/InstanceWithSlots.di
new file mode 100644
index 0000000..8c549ee
--- /dev/null
+++ b/Uml2OpcuaTransformationTests/InstanceWithSlots.di
@@ -0,0 +1,2 @@
+
+
diff --git a/Uml2OpcuaTransformationTests/InstanceWithSlots.notation b/Uml2OpcuaTransformationTests/InstanceWithSlots.notation
new file mode 100644
index 0000000..c554007
--- /dev/null
+++ b/Uml2OpcuaTransformationTests/InstanceWithSlots.notation
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Uml2OpcuaTransformationTests/InstanceWithSlots.uml b/Uml2OpcuaTransformationTests/InstanceWithSlots.uml
new file mode 100644
index 0000000..c9f8545
--- /dev/null
+++ b/Uml2OpcuaTransformationTests/InstanceWithSlots.uml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Uml2OpcuaTransformationTests/InstanceWithSlots.xml b/Uml2OpcuaTransformationTests/InstanceWithSlots.xml
new file mode 100644
index 0000000..35f089d
--- /dev/null
+++ b/Uml2OpcuaTransformationTests/InstanceWithSlots.xml
@@ -0,0 +1,104 @@
+
+
+
+ Instance
+
+
+ i=6
+ i=45
+ i=47
+ i=85
+ i=12
+ i=78
+ i=40
+ i=37
+ i=63
+ i=58
+ i=35
+
+
+ Axes
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1000
+
+
+
+ SN
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1000
+
+
+ #000000
+
+
+
+ Manufacturer
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1000
+
+
+ ABB
+
+
+
+ Description
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1000
+
+
+
+ Class5Type
+
+ BaseObjectType
+ ns=1;i=1001
+ ns=1;i=1002
+ ns=1;i=1003
+ ns=1;i=1004
+
+
+
+ Description
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1005
+
+
+
+ Manufacturer
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1005
+
+
+ ABB
+
+
+
+ SN
+
+ BaseDataVariableType
+ ModellingRule_Mandatory
+ ns=1;i=1005
+
+
+ #005001
+
+
+
+ Class5Instance
+
+ ns=1;i=1000
+ ObjectsFolder
+
+
+
\ No newline at end of file