blob: 33c2c42bbc3a103862e5008ba9ad687f3f42913e [file] [log] [blame]
=Rpy Interoperability Developer=
This documentation talks about the import of models created with the software '''IBM Rational Rhapsody''' into Papyrus. '''IBM Rational Rhapsody''' is developed by the IBM company. In this documentation, we reference this software as '''Rhapsody'''.
==Which Rhapsody version models are supported?==
The migration tool has been developed with IBM Rhapsody 8.0.3. Nevertheless, it should work with previous and next versions.
==Where are located the Papyrus Intereoperability Rpy plugins?==
All Papyrus Rpy user plugins are stored in the Papyrus git ''org.eclipse.papyrus-interoperability.git'', into the subfolder ''rpy''.
==Papyrus Interoperability Rpy Metamodel==
*'''org.eclipse.papyrus.interoperability.rpy.metamodel''',
*'''org.eclipse.papyrus.interoperability.rpy.metamodel.edit''',
*'''org.eclipse.papyrus.interoperability.rpy.metamodel.editor''':
These 3 plugins provide the papyrus umlrpy metamodel based on Ecore. They describe the internal Rhapsody metamodel.
The models created with this metamodel used the file extension ''*.umlrpy''. The QVTo transformations are applied on these files to create the Papyrus UML models.
===How has been created this metamodel?===
Rhapsody and Papyrus are representing differently similar concepts. The Rhapsody to Papyrus import process is implemented as a set of mapping rules between those two representations.
In order to express the mapping rules, a description of Rhapsody representation of UML and graphical concepts has been implemented with a so-called “ecore metamodelâ€?.
This metamodel has been built thanks to an analysis of two complementary public informations:
*the public java API providing a first list of the concepts and their inheritance relationship. The documentation of this API located in Doc/java_api/index.html of Rhapsody install folder. The public java API is located in 'Share/JavaAPI/rhapsody.jar'.
*the list of 150+ examples provided in the Sample directory. Those examples provided a good overview of all the concepts involved in Rhapsody models and how they are serialized in textual files. In order to accelerate the development, this analysis process has been automated in “one shotâ€? script which is not part of the delivered software.
However, an automated update process is provided as a “developer featureâ€? : when a user provides a new Rhapsody model containing concepts which had not been encountered in the analyzed examples, the metamodel update with those new concepts can be automated. This features is made to accelerate the implementation of a new mapping rule to an equivalent Papyrus concept.
To update the metamodel, you can use the plugin '''org.eclipse.papyrus.interoperability.rpy.toolsmiths.api.discovery'''
*we also update this metamodel to be ease the development of the QVto transformation. That's why it is possible you met a property or an inheritance which doesn't exist in pure Rhapsody. In this case this property comes from a hand change done by a developer to ease the QVTo transformation writting process. It is not embarrassing to use a wrong EMF rhapsody metamodel to go from Rhapsody to Papyrus, because in this case, it will be more permissive. Nevertheless, it will be a problem to use it later to transform a Papyrus model into a Rhapsody model.
*It seems that the object '''IModelElement''' is the common ancestor to Rhapsody semantic element. Be careful with these objects:
**in Rhapsody the '''Diagram''' concept is a semantic element (and not a graphical element). Diagram can be stereotyped
**'''ISysMLPort''' is not a stereotype but a metamodel element for Rhapsody.
==Papyrus Interoperability Rpy plugins==
*'''org.eclipse.papyrus.interoperability.rpy.metamodel''',
*'''org.eclipse.papyrus.interoperability.rpy.metamodel.edit''',
*'''org.eclipse.papyrus.interoperability.rpy.metamodel.editor''':
**Please, see description in previous part.
*'''org.eclipse.papyrus.interoperability.rpy.blackboxes''':
** This plugin provides some useful blackboxes (java code). They are called by the QVTo transformations.
** These blackboxes are not embedded in the same plugin than the QVTo transformations to avoid compilation errors at the developer level and ease the development itself.
*'''org.eclipse.papyrus.interoperability.rpy.geometry''':
**This plugin provides objects to represent Rhapsody graphical elements and manipulate them easily to get their size and their location.
*'''org.eclipse.papyrus.interoperability.rpy.parser''',
*'''org.eclipse.papyrus.interoperability.rpy.parser.ui''':
** These plugins are used to parse the Rhapsody files (''*.rpy'' and others)
*'''org.eclipse.papyrus.interoperability.rpy.toolsmiths.api.discovery''':
**It is a developer plugin
**This plugin is not delivered, but it is build (a pom.xml file is provided)
**This plugin allows to update Rpy EMF metamodel when we meet models inconsistent with the current one.
*'''org.eclipse.papyrus.interoperability.rpy''':
**This plugin uses the other plugins described previously. It provides the API to convert a ''*.rpy'' into a Papyrus model (''*.uml'', ''*.notation'', ''*.di'' and ''*.properties'' files).
In addition, there are the plugins '''org.eclipse.papyrus.uml.m2m.qvto.common''' and '''org.eclipse.papyrus.uml.m2m.qvto.common.blackboxes''' located on the git org.eclipse.papyrus.git in the folder '''plugins/uml/m2m'''. These plugins group common code used by Rpy, RSA and Sysml14 interoperability tools.
JUnit tests are provided too. They use EMF-Compare to check that the imported models continues to be equals to the expected one.
==How does the migration process work?==
The migration process is done in 3 steps:
#the ''*rpy'' file is parsed by the XText parser (plugin '''org.eclipse.papyrus.interoperability.rhapsody.parser''') and converted into a first simple model using a first EMF metamodel, '''RpySyntax''', provided by this plugin, then
#this first model is converted into a set of ''*.umlrpy'' by the class '''org.eclipse.papyrus.interoperability.rpy.importer.UMLRpyImporter'''. There is a ''*.umlrpy'' file for the initial selected ''*rpy'' file, and one other for each subpackage of the imported Rhaposdy model. At the end of this process, we transform these files into the Papyrus UML model.
#In the Rhapsody model, there are references to objects provided by Rhapsody Libraries (types, stereotypes, ...) . As we can't reuse them directly (for legal reason), we create "proxy object" during the creation of the ''*.umlrpy'' file with an EAnnotation referencing the name of the Rhapsody file providing it. This information is used later in the process by the QVto transformation.
==QVTo Informations==
The QVTo files are stored in the plugin '''org.eclipse.papyrus.interoperability.rpy'''.
===Cast===
Casting collection doing [Type] seems change arbitrary the order of the elements. It is a pattern to avoid.
===Transformation files===
*Transformation file have a kind of constructor preceded by the transform keyword and contains a method main. They are registered with the extension point '''org.eclipse.m2m.qvt.oml.runtime.qvtTransformation''' as transformation.
*Library file have a name preceded by the keyword library. They must be registered with the extension point '''org.eclipse.m2m.qvt.oml.runtime.qvtTransformation''', as transformation or as library.
===How are chained the QVTo transformations?===
*All transformations must be called in the same context. That's why there is a kind of 'master' transformation calling the others. It is not possible to call them separately, because calling them separately we won't be able to find the result of a previous mapping using <code>resolve/invresolve</code> function.
*Here, this is the transformation <code>Rpy2PapyrusNotation</code> which call the others following this order:
*<code>Rpy2PapyrusSemanticElements</code>,
*then calls <code>SemanticInternationalization</code>
*then calls <code>SysML11Profile</code>,
*then calls <code>SysML11Diagrams</code> which calls the qvto transformations for
**<code>InternalBlockDiagram</code>,
**<code>BlockDefinitionDiagram</code> and
**<code>ParametricDiagram</code>,
**and, in addition, it completes the ''*.properties'' file with the label of the diagram when they exist.
===Inheritance===
It seems possible, but not yet used.
===How to develop the QVTo transformation?===
*The development has been done with all required plugins in the workspace.
**In the first Eclipse instance, the plugin owning the QVTo files (org.eclipse.papyrus.migration.rhapsody) doesn't compile because QVTo builder isn't able to resolve dependencies when they are in the same workspace. Moreover blackboxes registered in a plugin.xml can't be resolved.
**We launch a 2nd Eclipse to write QVTo transformation with no compilation error
**We launch a third Eclipse to launch transformation and check the result
===How to debug QVTo transformation?===
It is possible to use breakpoint to debug QVTo transformation, but in this case you must use the Operatinal QVT Interpreter provided as Debug tool of Eclipse.
[[Image:images/dev/QVTo_debugging.png|frame|none|QVTo Debugging view]]
===QVTo Tricks===
Here, we describe the main QVTo keyword to know:
*<code>mapping</code> it allows to declare a mapping method between two objects. It can have parameter. The resulting object is created before the first line of the mapping. If you want avoid to create a new object, you can look it for the object to return using the <code>init{your code}</code> block. Calling a given mapping for a given object will create a new object the first time and will return it other time. No new object will be created calling a given mapping several time with the same parameters.
*<code>init{your code}</code> it allows to assign the result without creating an object. If at the end of this block, the result is <code>null</code>, the object will be created.
*<code>disjuncts</code> it allows to declare a method dispatching an action to one of the others declared method.
*<code>when</code> it allows to define a condition to allow the mapping (always used by a mapping called by a disjuncts mapping)
*<code>result</code> keyword defining the result of a mapping
*<code>init</code> to start a mapping, it allows to initializing the result without create an element
*<code>@</code> allows to define the file owning the object when the transformation has several output files.
*QVTo/OCL are not able to cast UML Element or Rpy Element in an other object inherited from an other metamodel implicitly. So to convert a <code>uml.Element</code> into <code>ecore.EObject</code> you need to write the cast, otherwise it won't compile. So you can write : <code>Element.oclAsType(EObject)</code> or <code>Element![EObject]</code> to do that.
*To ease transformation writing, we advice to use <code>disjuncts</code> each time it is possible to create common method. To our mind, the best common method will be declared as this example: <code>umlrpy::IModelElement::commonMethod:uml:Element disjuncts</code>. This pattern ease the call to <code>resolve/invresolve</code> function to retrieve an object previously created ignoring the real mapping method used. As an object is created only one time, you can also replace the <code>resolve/invesolve</code> functions, calling the mapping directly.
*<code>resolveOne/invresolveOne</code> could seems interesting, but often an object can be used as entry of several mapping. For example, we use <code>IObjectLink</code> to create the UML Connector and its two ConnectorEnds.
* How to find easily the result of previously executed transformation ?
**The most common usecase is to set the element (EObject) representing a View during the graphical transformation. The QVTo method called resolved required to know which mapping was used to create the semantic element. The best solution is to always call the same common method to do the mapping. 2 implementations are possible:
***create a common mapping from a given type in the source metamodel to the most generic type of the target metamodel. This mapping will call the good submapping using ''disjunct'' and ''when'' QVTo keyword. Use resolved/invresolved to find the good object.
***after a mapping call a dummy method used as map (key,value) to store the result of the mapping:
<code>
mapping EObject::StoreSourceAndResult(res : EObject) : EObject {
init { result := res }
}
</code>
*When do I apply stereotype ?
It could seem a good idea to apply them when required in the mapping method, but it is not possible, because
###the result of the mapping is not yet in stored in the resource, so we get a NPE (main reason),
###in some case stereotype properties reference UML object not yet mapped (or stereotype application of others objects),
###more complex to override when we want extends a transformation to manage others profiles.
That's why we make a second run to apply profiles and stereotypes on the objects
*How to get Stereotype Application to edit its feature ?
**the resource edited during the transformation is in an other resourceset than the object given as parameter of the transformation, so this code deosn't work:
<code>
Stereotype firstStereotype=...//(coming from a parameter of the transformation)
element.applyStereotype(firstStereotype);
element.setValue(firstStereotype,"propName", newValue);//doesn't work
</code>
so we must do :
<code>
Stereotype firstStereotype=...//(coming from a parameter of the transformation)
element.applyStereotype(firstStereotype);
Stereotype secondStereotype=element.getAppliedStereotype(firstStereotype.getQualifiedName())
element.setValue(secondStereotype,"propName", newValue);//works, first and secondStereotype are equals; their resource have the same URI, but 2 instance of the same resource is loaded
</code>
Of course, in case of static profile, we can create the EClass represented the UML Stereotype in a mapping method too.
==General Tricks==
*When the ''*rpy'' didn't change, to test your code quicker, you can select the file ''*.umlrpy'' directly to import it as Papyrus model.
==Java code==
The plugin '''org.eclipse.papyrus.interoperability.common''' is a refactoring of the code provided for RSA migration tool. A part of the embedded code initially written for RSA migration tool is now embedded in this plugin used by Rpy migration tool, but not yet used.
The QVTo transformation is launched by the class <code>org.eclipse.papyrus.interoperability.rpy.transformations.RpyImportTransformationLauncher</code>.
The creation of the ''*.umlrhapsody'' file is done by the class <code>org.eclipse.papyrus.interoperability.rpy.importer.SelectedRpyFilesImporter</code>.
==Versioning==
To ease future fixes for generated corrupted models, an '''EMF EAnnotation''' is added during the transformation to the root of the UML model and to all created diagrams. This EAnnotation contains:
*the version of the Papyrus Rpy Migration Tool,
*the version of the Rhapsody software used to create the model, and
*the name of the Rhapsody model.
This work is done by the QVTo library <code>RpyToPapyrusUtils</code>, with the helper method <code>createEAnnotationForVersioning</code>.
==Diagram Styling==
As we want to get the same style in import models than in the Rhapsody source model, we need to add EAnnoation PapyrusCSSForceValue to override the styling done by CSS stylesheet. The method to create a such EAnnotation is provided by the QVTo library <code>RpyToPapyrusDiagamCommon</code>, by the helper <code>createCSSForceValue</code>.