| /***************************************************************************** |
| * Copyright (c) 2016 CEA LIST. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation |
| *****************************************************************************/ |
| |
| import org.eclipse.papyrus.interoperability.rpy.blackboxes.sysml11.NestedConnectorEndBlackboxes; |
| import org.eclipse.papyrus.interoperability.rpy.blackboxes.Rpy2PapyrusNotationBlackboxes; |
| import org.eclipse.papyrus.interoperability.rpy.blackboxes.uml.UMLRpySemanticHelper; |
| import Rpy2PapyrusSemanticElements; |
| import RpyToPapyrus; |
| import RpyUtils; |
| import SysMLRpyUtils; |
| |
| modeltype umlrpy "strict" uses 'http://www.eclipse.org/Papyrus/UMLRpy/1.0.0'; |
| modeltype uml "strict" uses 'http://www.eclipse.org/uml2/5.0.0/UML'; |
| modeltype sysml11 "strict" uses 'http://www.eclipse.org/papyrus/0.7.0/SysML'; |
| modeltype ecore "strict" uses 'http://www.eclipse.org/emf/2002/Ecore'; |
| modeltype UMLPrimitivesTypes "strict" uses 'http://www.eclipse.org/uml2/5.0.0/Types' ; |
| |
| |
| /** |
| * |
| * WARNING : ISysMLPort is a part of Rpy metamodel and doesn't come from the SysML Rpy Profile |
| * |
| * |
| */ |
| transformation SysML11Profile(in inModel:umlrpy, out outModel:uml, in Sysml11Profile:sysml11, in primitives:UMLPrimitivesTypes) |
| extends Rpy2PapyrusSemanticElements(in inModel:umlrpy, out outModel:uml, in primitives:UMLPrimitivesTypes) |
| |
| { |
| main() { |
| if (isRpySysMLProfileApplied() and sysml11<>null ) { |
| log("Start SysML Profiles and Stereotypes Application"); |
| //if yes apply it to the output model |
| var model: Model := outModel.rootObjects()![uml::Model]->any(true); |
| |
| // apply sysml 1.1 profile with all sub profiles |
| var sysml11Profiles : Set(Profile) := Sysml11Profile.objectsOfType(Profile); |
| |
| sysml11Profiles->forEach(profile) { |
| model.applyProfile(profile); |
| }; |
| |
| //apply SysML 1.1 stereotype when it is applied in Rpy Model |
| inModel.objects()->select(rpy | not rpy.oclIsKindOf( GraphElementsType))->selectByKind(EObject).map applyRequiredSysML11Stereotype(); |
| |
| //apply NestedConnectorEnd stereotype |
| outModel.objects()->selectByKind(uml::ConnectorEnd).map applySysML11ConnectorEndStereotype(); |
| |
| log("End SysML Profiles and Stereotypes Application"); |
| }; |
| }; |
| } |
| |
| /** |
| * This mapping create the NestedConnectorEnd stereotype when required for the given object |
| * |
| */ |
| mapping uml::ConnectorEnd::applySysML11ConnectorEndStereotype() : sysml11::blocks::NestedConnectorEnd when {getNestedConnectorEndPropertyPath(self)->size()>0}{ |
| base_ConnectorEnd:=self; |
| propertyPath:=getNestedConnectorEndPropertyPath(self); |
| } |
| |
| |
| /** |
| * |
| * Return true if the Rpy SysML Profile is applied on the Rpy model |
| */ |
| query isRpySysMLProfileApplied():Boolean { |
| var ret:Boolean = false; |
| var isProfiledModel:Boolean:=inModel.objectsOfType(IStereotype)->size()>0; |
| if (isProfiledModel) { |
| inModel.objectsOfType(IStereotype)->forEach(stereotype){ |
| if(stereotype.isARpySysMLStereotype()){ |
| ret:= true; |
| break; |
| } |
| } |
| }; |
| return ret; |
| } |
| |
| |
| //--------------------------Here we are working on the Rpy Stereotypes-------------- |
| |
| /** |
| * This method manage the stereotype application from Rpy to Papyrus for a set of Rpy element |
| * |
| * TODO : edit the Rpy metamodel to get a common ancestor to manipulate easily the stereotyped element in Rpy |
| */ |
| mapping ecore::EObject::applyRequiredSysML11Stereotype() disjuncts |
| ecore::EObject::applyStereotypeFromIClass, |
| ecore::EObject::applyStereotypeFromIType_To_InstanceSpecification, |
| ecore::EObject::applyStereotypeFromIType_To_DataType, |
| ecore::EObject::applyStereotypeFromIType_To_Class, |
| ecore::EObject::applyStereotypeFromIType_To_Type, |
| ecore::EObject::applyStereotypeFromISysMLPort, |
| ecore::EObject::applyStereotypeFromIPart, |
| ecore::EObject::applyStereotypeFromIAttribute, |
| ecore::EObject::applyStereotypeFromIInformationFlow |
| {} |
| |
| /** |
| * This method cross the stereotypes applied on the IClass and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIClass() when {self.oclIsTypeOf(IClass) /*and not self.oclAsType(IClass).Stereotypes->isEmpty()*/}{ //test on stereotype must be done in the method, because we always need to do some thing for IClass |
| var rpyElement:IClass:=self.oclAsType(IClass); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(EObject::generalMappingToUMLElement, uml::Element); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| }; |
| |
| //apply Block and PropertySpecificType on some class |
| var nestedClassesForPart:Sequence(IClass):=rpyElement.Associations[IPart]->select(current | current.implicitClass<>null).implicitClass.oclAsSet(); |
| nestedClassesForPart->forEach(current){ |
| var umlClass:uml::Class:=current.resolveone().oclAsType(uml::Class); |
| umlClass.map applySysML11Stereotype(current.oclAsType(EObject), "Block"); |
| umlClass.map applySysML11Stereotype(current.oclAsType(EObject), "PropertySpecificType"); |
| }; |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IType and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIType_To_InstanceSpecification() when {self.oclIsTypeOf(IType) and not self.oclAsType(IType).Stereotypes->isEmpty() and self.resolveoneIn(EObject::iTypeToUMLInstanceSpecification, InstanceSpecification)<>null}{ |
| var rpyElement:IType:=self.oclAsType(IType); |
| //we look for the created uml element |
| var umlElement:Element:=self.resolveoneIn(EObject::iTypeToUMLInstanceSpecification, InstanceSpecification); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IType and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIType_To_DataType() when {self.oclIsTypeOf(IType) and not self.oclAsType(IType).Stereotypes->isEmpty() and self.resolveoneIn(EObject::iTypeToUMLDatatype, DataType)<>null}{ |
| var rpyElement:IType:=self.oclAsType(IType); |
| //we look for the created uml element |
| var umlElement:Element:=self.resolveoneIn(EObject::iTypeToUMLDatatype, DataType); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| //TODO umlDataType and umlClass are probably useless now, waiting for JUnit tests to remove them from this method |
| /** |
| * This method cross the stereotypes applied on the IType and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIType_To_Class() when {self.oclIsTypeOf(IType) and not self.oclAsType(IType).Stereotypes->isEmpty() and self.resolveoneIn(EObject::iTypeToUMLClass, Class)<>null}{ |
| var rpyElement:IType:=self.oclAsType(IType); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(EObject::iTypeToUMLClass, Class); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| }; |
| |
| //in all case, we apply block on the class |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName("Block")); |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IType and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIType_To_Type() when {self.oclIsTypeOf(IType) and not self.oclAsType(IType).Stereotypes->isEmpty() and self.resolveoneIn(EObject::generalMappingToUMLElement, Type)<>null}{ |
| var rpyElement:IType:=self.oclAsType(IType); |
| //we look for the created uml element |
| var umlElement:Element:=self.resolveoneIn(EObject::generalMappingToUMLElement, Type); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the ISysMLPort and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromISysMLPort() when {self.oclIsTypeOf(ISysMLPort) and not self.oclAsType(ISysMLPort).Stereotypes->isEmpty()}{ |
| var rpyElement:ISysMLPort:=self.oclAsType(ISysMLPort); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(umlrpy::IRelation::iRelationToUMLElement); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IPart and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIPart() when {self.oclIsTypeOf(IPart) and not self.oclAsType(IPart).Stereotypes->isEmpty()}{ |
| var rpyElement:IPart:=self.oclAsType(IPart); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(umlrpy::IPart::iPartToUMLElement); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IAttribute and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIAttribute() when {self.oclIsTypeOf(IAttribute) and not self.oclAsType(IAttribute).Stereotypes->isEmpty()}{ |
| var rpyElement:IAttribute:=self.oclAsType(IAttribute); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(IVariable::iVariableToUMLElement, uml::Property); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| /** |
| * This method cross the stereotypes applied on the IInformationFlow and call the method to apply them on the equivalent uml element |
| */ |
| mapping ecore::EObject::applyStereotypeFromIInformationFlow() when {self.oclIsTypeOf(IInformationFlow) and not self.oclAsType(IInformationFlow).Stereotypes->isEmpty()}{ |
| var rpyElement:IInformationFlow:=self.oclAsType(IInformationFlow); |
| //we look for the created uml element |
| var umlElement:Element:=rpyElement.resolveoneIn(umlrpy::IInformationFlow::iInformationFlowToUMLElement); |
| if(umlElement<>null){ |
| rpyElement.Stereotypes->selectByType(umlrpy::IStereotype)->forEach(current){ |
| umlElement.map applySysML11Stereotype(rpyElement.oclAsType(EObject), getSysML11StereotypeName(current.name)); |
| } |
| } |
| } |
| |
| |
| //--------------------------Here we are working on the UML Stereotypes------------------- |
| /** |
| * Common method to apply a UML stereotype from the rpy element and from its name to a UML Element |
| */ |
| mapping uml::Element::applySysML11Stereotype(rpyElement:EObject, umlSteName:String):EObject disjuncts |
| uml::DataType::applySysML11ValueType, |
| uml::InstanceSpecification::applySysML11Dimension, |
| uml::InstanceSpecification::applySysML11Unit, |
| uml::Class::applySysML11Block, |
| uml::Property::applySysML11FlowProperty, |
| uml::Port::applySysML11FlowPort, |
| |
| //default mapping method |
| uml::Element::applySysML11Stereotype_DefaultMapping |
| {} |
| |
| /** |
| * Default mapping to apply Sysml11 stereotype |
| * |
| */ |
| mapping uml::Element::applySysML11Stereotype_DefaultMapping(rpyElement:EObject, umlSteName:String):EObject when {getSysML11Stereotype(umlSteName)<>null}{ |
| init { |
| var stereotypeToApply:Stereotype:=getSysML11Stereotype(umlSteName); |
| self.applyStereotype(stereotypeToApply); |
| result:=self.getAppliedStereotype(stereotypeToApply.getQualifiedName()).oclAsType(EObject); |
| } |
| } |
| |
| /** |
| * |
| * This method apply the stereotype SysML FlowPort |
| */ |
| mapping uml::Port::applySysML11FlowPort(rpyElement:EObject, stereotypeName:String):EObject when{rpyElement.oclIsKindOf(ISysMLPort) and stereotypeName="FlowPort"}{ |
| init{ |
| var stereotypeApplication:sysml11::portandflows::FlowPort:= object sysml11::portandflows::FlowPort{ |
| base_Port:=self; |
| direction:=getSysML11FlowDirection(rpyElement.oclAsType(ISysMLPort).direction); |
| |
| if(not self.isAtomic(rpyElement.oclAsType(umlrpy::ISysMLPort))){ |
| //If the FlowPort is atomic (by its type), then isAtomic=True, the direction must be specified (has a value), and |
| //isConjugated is not specified (has no value). |
| isConjugated:=rpyElement.oclAsType(ISysMLPort).isConjugated(); |
| }else{ |
| isConjugated:=false; |
| }; |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| /** |
| * @param a ISysMLPort |
| * |
| * @return true if the port is atomic and false otherwise |
| * |
| */ |
| helper uml::Port::isAtomic(rpyPort:umlrpy::ISysMLPort): Boolean{ |
| var isAtomic:Boolean:=true; |
| if(self.type<>null){ |
| //1. we need to call the mapping for stereotype applied on the type of the port to know if it is stereotyped with FlowSpecification |
| rpyPort.oclAsType(ISysMLPort).otherClass.oclAsType(EObject).map applyRequiredSysML11Stereotype(); |
| |
| //2. now we could check the stereotype applied on the type of the port |
| var flowSpec:uml::Stereotype:=self.type.getAppliedStereotype(getSysML11Stereotype("FlowSpecification").getQualifiedName()); |
| if (flowSpec<> null) { |
| isAtomic:=false; |
| }; |
| }; |
| return isAtomic; |
| } |
| |
| /** |
| * |
| * This method apply the stereotype SysML FlowPort |
| */ |
| mapping uml::Property::applySysML11FlowProperty(rpyElement:EObject, stereotypeName:String):EObject when{rpyElement.oclIsKindOf(IAttribute) and stereotypeName="FlowProperty"}{ |
| init{ |
| var stereotypeApplication:sysml11::portandflows::FlowProperty:= object sysml11::portandflows::FlowProperty{ |
| base_Property:=self; |
| |
| //we have model with 2 kind of declaration for the same thing... |
| //the first way! |
| var dir:String:=rpyElement.oclAsType(IAttribute).Tags->any(name="direction" and typeOf.oclAsType(IType).name="FlowDirection").ValueSpecifications->any(true).oclAsType(ILiteralSpecification).value; |
| //the 2nd way is required |
| if(dir.oclIsUndefined()){ |
| //probably due to an error in the model, but in soem case we met RhpString |
| dir:=rpyElement.oclAsType(IAttribute).Tags->any(name="direction" and typeOf.oclAsType(IType).name="RhpString").ValueSpecifications->any(true).oclAsType(ILiteralSpecification).value; |
| }; |
| |
| direction:=getSysML11FlowDirection(dir); |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| /** |
| * This method apply the stereotype Block |
| */ |
| mapping uml::Class::applySysML11Block(rpyElement:EObject, stereotypeName:String):EObject when{stereotypeName="Block"}{ |
| init{ |
| var stereotypeApplication:sysml11::blocks::Block:= object sysml11::blocks::Block{ |
| base_Class:=self; |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| /** |
| * This method apply the stereotype Dimension |
| */ |
| mapping uml::InstanceSpecification::applySysML11Dimension(rpyElement:EObject, umlSteName:String):EObject when {umlSteName="Dimension"}{ |
| init{ |
| var stereotypeApplication:sysml11::blocks::Dimension:= object sysml11::blocks::Dimension{ |
| base_InstanceSpecification:=self; |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| /** |
| * This method apply the stereotype Unit |
| */ |
| mapping uml::InstanceSpecification::applySysML11Unit(rpyElement:EObject, umlSteName:String):EObject when {umlSteName="Unit" and rpyElement.oclIsKindOf(IType)}{ |
| init{ |
| var stereotypeApplication:sysml11::blocks::Unit:= object sysml11::blocks::Unit{ |
| base_InstanceSpecification:=self; |
| |
| //manage the dimension field |
| var tt:umlrpy::ITag=rpyElement.oclAsType(IType).Tags->select(t | t.name="dimension")->any(true); |
| var iinstancespec:umlrpy::IInstanceValue=tt.ValueSpecifications->selectByKind(umlrpy::IInstanceValue)->any(true); |
| if(iinstancespec<>null){ |
| var val = iinstancespec.value; |
| var res:uml::InstanceSpecification = val.resolveoneIn(EObject::iTypeToUMLInstanceSpecification); |
| dimension:=res.map applySysML11Stereotype(val.oclAsType(EObject),"Dimension").oclAsType(sysml11::blocks::Dimension); |
| } |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| mapping uml::DataType::applySysML11ValueType(rpyElement:EObject, umlSteName:String):EObject when {umlSteName="ValueType" and rpyElement.oclIsKindOf(IType)}{ |
| init{ |
| var stereotypeApplication:sysml11::blocks::ValueType:= object sysml11::blocks::ValueType{ |
| base_DataType:=self; |
| |
| //manage the dimension field |
| var dimensionTag:umlrpy::ITag=rpyElement.oclAsType(IType).Tags->select(t | t.name="dimension")->any(true); |
| var dimensionInstanceIInstancespec:umlrpy::IInstanceValue=dimensionTag.ValueSpecifications -> selectByKind(umlrpy::IInstanceValue)->any(true); |
| if(dimensionInstanceIInstancespec<>null){ |
| var val = dimensionInstanceIInstancespec.value; |
| var res:uml::InstanceSpecification = val.resolveoneIn(EObject::iTypeToUMLInstanceSpecification); |
| dimension:=res.map applySysML11Stereotype(val.oclAsType(EObject),"Dimension").oclAsType(sysml11::blocks::Dimension); |
| }; |
| |
| //manage the unit field |
| var unitTag:umlrpy::ITag=rpyElement.oclAsType(IType).Tags->select(t | t.name="unit")->any(true); |
| var unitInstanceIInstancespec:umlrpy::IInstanceValue=unitTag.ValueSpecifications -> selectByKind(umlrpy::IInstanceValue)->any(true); |
| if(unitInstanceIInstancespec<>null){ |
| var val = unitInstanceIInstancespec.value; |
| var res:uml::InstanceSpecification = val.resolveoneIn(EObject::iTypeToUMLInstanceSpecification); |
| unit:=res.map applySysML11Stereotype(val.oclAsType(EObject),"Unit").oclAsType(sysml11::blocks::Unit); |
| }; |
| }; |
| result:=stereotypeApplication.oclAsType(EObject); |
| } |
| } |
| |
| |
| /** |
| * |
| * Return the SysML 1.1 Stereotype for the given string or null if not found |
| */ |
| query getSysML11Stereotype(rpyStereotypeName:String ) :uml::Stereotype { |
| return Sysml11Profile.objectsOfType(Stereotype)![name=getSysML11StereotypeName(rpyStereotypeName)]; |
| } |
| |
| /** |
| * Return the SysML 1.1 name corresponding to the Rpy SysML Name |
| */ |
| query getSysML11StereotypeName(rpyStereotypeName:String): String{ |
| var sysml11SteName:=switch{ |
| case (rpyStereotypeName="flowSpecification") "FlowSpecification"; |
| case (rpyStereotypeName="flowProperty") "FlowProperty"; |
| case (rpyStereotypeName="flowPort") "FlowPort"; |
| case (rpyStereotypeName="block") "Block"; |
| //all case where the Rpy SysML Stereotype name is the same than the Papyrus SysML Name |
| case (true) rpyStereotypeName; |
| }; |
| return sysml11SteName |
| } |
| |
| /** |
| * |
| * This method convert the rhaspody flow direction into the SysML FlowDirection |
| */ |
| query getSysML11FlowDirection(rpyDirection:String) : sysml11::portandflows::FlowDirection{ |
| var direction: sysml11::portandflows::FlowDirection; |
| direction:= switch { |
| case (rpyDirection="In") sysml11::portandflows::FlowDirection::_in; |
| case (rpyDirection="Out") sysml11::portandflows::FlowDirection::_out; |
| case (rpyDirection="InOut") sysml11::portandflows::FlowDirection::_inout; |
| case (rpyDirection="Bidirectional") sysml11::portandflows::FlowDirection::_inout; |
| case (true) sysml11::portandflows::FlowDirection::_inout; |
| }; |
| return direction; |
| } |