A complex transformation process is the creation of a gmf editor. This is the process also used to generate this plug in. Like the gmf dashboard you can use it as an execution board for the whole transformation and generation process, but unlike it you can fully customize it, because this is an editor for such model. It’s support inheriting what gmf not directly does. The big picture is M2M round tip, if you change your ecore model you can regenerate all resources. The main concept is convention over declaration. Only if you want to change the default behavior you need to define it.
You can control the transformation in three ways :
You start by selecting your ecore model file and select New -> other
Or you can initialize only a start configuration and a custom atl file via context menu on an ecore model file (*.ecore), the transformations are expected in the template project.
You select the target container and the input model. If your project isn’t an ATL project you can add the ATL nature to the project.
After finishing the wizard the nessesary files are created and you can open up the callchain_diagram file. A folder gmf is created, it contains the transformations, a file xxx_custom.atl is created in the model folder, this file is the declaration part of the transformation, here you can define exceptions from the default behavior. Also two launch configuration are created, one for bootstrapping and one for the main process.
The first time it is nessesary to create all resources, before you can start with the main generation process. The bootstrapping gmf diagram contains the transformation for this bootstrapping process. Just start the bootstrapToolTemplate call.
Three models are created, a graphtemplate containing the default graphmappings, a custom graphmapping, and a tool model. The custom graphmapping will override the default one, so here you would define your exceptions from the default behavior. Just rename your tool.gmftool to xxxx the tool model is quite simple so I had decided to directly use the customized model. With this copy of the tool model you will define your tool pallete as usual. In roundtip you will need to make the changes manually. But the tooling definition is about grouping items, and in my opinion the default editor, the EMF one, is a good editor for such task.
This is the main process cycle.
It starts by create and merging the definition data into the mapping file. We let the gmf generator create the genmodel, and refine it in a transformation. Afterwards we use the gmf generator again to produce the diagram plug in.
The main hook is the file xxx.atl it contains declarations of exceptions from the normal transformation process. So at first you will need to know the default process.
Each eClass will be tranformed to a topNodeReference if, it’s not the diagram node, it’s not an type based link, it’s not contain in an other eClass, and it’s not excluded. For each topNodeReference a nodeMapping is created, with the resolved tool and the resolved diagramNode. An domainSpecialization ocl constrain is created linking the node tight to the eClass.
Each eAttribute will be transformed to a featureLabelMapping if, the eClass containing it is not excluded, and it self it not excluded. It will be linked with the corresponding diagramLabel and the viewPattern will be set to the defined value, mostly the default one.
An eReference will transformed to a referencedBaseLink if, it’s not a containment reference, and of course it’s not excluded.
The file based customizing.
-- @atlcompiler atl2006
-- @nsURI GMF_TOOL=http://www.eclipse.org/gmf/2005/ToolDefinition
-- @nsURI ECORE=http://www.eclipse.org/emf/2002/Ecore
------------------------------------------------------------
--
--
library ecore2gmfTool_custom;
-- eclasses displayed as link
helper def : linknames : Sequence(String) = Sequence{
'MMAlias','ModelAlias','Transition'
};
-- link containments : the link eclass , the feature it's stored in
helper def : linkContainments : Map(String,String) = Map{
('ModelAlias','Call.in')
,('Transition','NamedSwitch.transitions')
};
-- the link targets feature : the identifier, and the feature as qname
helper def : linkTarget : Map(String,String) = Map{
('Model.mm','Model.mm'),
('AtlRes.superimpose','AtlRes.superimpose'),
('Call.in','Call.in'),
('Call.libarys','Call.libarys'),
('Call.artifact','Call.artifact'),
('Generator.uses','Generator.uses'),
('Generator.produce','Generator.produce'),
('ModelAlias','ModelAlias.decoratedmodel'),
('MMAlias','MMAlias.decoratedmodel'),
('Comment.documentedElement','Comment.documentedElement'),
('Callable.next','Callable.next'),
('Call.out','Call.out'),
('Call.res','Call.res'),
('ModelAlias','ModelAlias.decoratedmodel'),
('MMAlias','MMAlias.decoratedmodel')
,('Transition','Transition.callable')
,('NamedSwitch.defaultCall','NamedSwitch.defaultCall')
};
--the source of a link
helper def : linkSource : Map(String,String) = Map{
--('ModelAlias','ModelAlias.decoratedmodel'),
--('MMAlias','MMAlias.decoratedmodel')
};
--ocl constraint for a link can be defined here
-- annotaion : link.sourcecontraint
helper def : linkConstraint : Map(String, TupleType(source:String,target:String) )
= Map{
('PredicateSwitch.trueCallable', Tuple{
source : String ='self <> oppositeEnd and (self.falseCallable <> oppositeEnd or self.falseCallable.oclIsUndefined())',
target : String ='true'} )
,('PredicateSwitch.falseCallable', Tuple{
source : String ='self <> oppositeEnd and (self.trueCallable <> oppositeEnd or self.trueCallable.oclIsUndefined())',
target : String ='true'} )
,('NamedSwitch.defaultCall', Tuple{
source : String ='self <> oppositeEnd and self.transitions -> select(t| t.callable = oppositeEnd)->isEmpty()',
target : String ='true'} )
,('Transition', Tuple{
source : String ='self <> oppositeEnd and (self.defaultCall <> oppositeEnd or self.defaultCall.oclIsUndefined())',
target : String ='true'} )
};
--the custom view pattern for feature labels (Qname,pattern)
helper def : customViewPatterns : Map(String,String) = Map{
};
-- classes not transformed
-- annotaion : excludeEClass
helper def : excludedEClasses : Sequence(String) = Sequence{
'Callable','Documentable','Eavaluateable'
,'Predicate'
,'Property'
,'PropertyPredicate'
,'PropertyHasValue'
,'PropertyExist'
,'ResourcePredicate'
,'ResourceExistPredicate'
,'CompositePredicate'
,'AndPredicate'
,'OrPredicate'
,'NotPredicate'
,'BooleanPredicate'
,'Switch'
,'NamedSwitch'
};
-- features not transformed
helper def : excludedEReference : Sequence(String) = Sequence{
'Call.enviorment'
,'Switch.enviorment'
,'Generator.enviorment'
,'ExternalCallable.enviorment'
,'Switch.allCallables'
,'ExternalCallable.delegatedCallable'
,'PropertyValueSwitch.property'
,'ResourcePredicate.resource'
,'Eavaluateable.predicate'
,'Comment.owner'
};
helper def : excludedEAttributes : Sequence(String) = Sequence{
'Calls.logDefault',
'Call.profile',
'Call.disableAttributeHelperCache',
'Call.printExecutionTime',
'Call.showSummary',
'Call.continueAfterErrors',
'Call.allowInterModelReferences',
'Callable.refreshWorkspace',
'Model.isTemporary',
'ModelAlias.isTemporary',
'ModelAlias.uri',
'ModelAlias.name',
'MMAlias.isTemporary',
'MMAlias.uri',
'MMAlias.name',
'MMAlias.handler',
'Generic_Generator.id',
'Generic_Generator.generatorType',
'StopCall.refreshWorkspace',
'ExternalCallable.refreshWorkspace',
'PropertyValueSwitch.refreshWorkspace',
'PredicateSwitch.refreshWorkspace',
'Generic_Generator.refreshWorkspace',
'Call.refreshWorkspace',
'Artifact.derived',
'AtlLibary.derived',
'AtlRes.derived',
'Model.derived',
'MM.derived',
'ModelAlias.derived',
'MMAlias.derived'
};
--
helper def : refLink() : Map(String,String) = Map{
-- ('CliAccountAssociation','CliAccountAssociation.account')
--,
};
-- the custom figure namen (eclassname , figurename)
-- uses a defined figure for this eClass
helper def : customFigureName : Map(String,String) = Map{
--('Useit_Generator','ug')
};
--the diagram element , the name of the eClass being the diagram node
helper def : diagram(): String = 'Calls';
-- the default viewpattern of the feature label
helper context ECORE!EAttribute def : toDefaultViewPattern() : String =
--self.name+' : {0}'
''
;
-- to define compartments
-- name of the compartment and the qualified name of the feature it stores
helper def : compartments : Map(String, Sequence(String)) =Map{
-- ('<CompartmentName>',Sequence{'<FeatureName>',...} )
};
-- the figure for an eclass
-- link containments : the eclass , figureName in the rule
-- annotation : figureName
helper def : figureNames : Map(String,String) = Map{
-- (<EclassName>,'svgFigure')
-- (<EclassName>,'label')
};
-- the svg uri for an eclass, applied if the figure is a svg figure
-- : the eclass , theUri
helper def : svgUris : Map(String,String) = Map{
-- ('MegaKonzern','platform:/plugin/de.urszeidler.shr.chracters.diagram/images/Konzern1.svg'),
};
-- a map of element names (eclasses or features) and label names
-- will be used to create diagram labels in elements not define by a feature
helper def : additionalLabels : Map(String,String) = Map{
('PredicateSwitch.falseCallable','FalseCallable'),
('PredicateSwitch.trueCallable','TrueCallable'),
('NamedSwitch.defaultCall','DefaultCallable')
};
-- a map of label names and the text value of that label
-- it also can contains the default values for other labels
helper def : additionalLabelValues : Map(String,String) = Map{
('FalseCallable','FALSE'),
('TrueCallable','TRUE'),
('DefaultCallable','DEFAULT')
};
-- output plugin name
helper def : plugin_name(): String = 'de.urszeidler.eclipse.callchain.diagram';
-- the used file extensions
helper def : fileextension_name(): String = 'callchain_diagram';
In the helper figureNames you can define the figure, for now only svgFigure, label and the defaultFigure exist. For the svgFigure in the helper svgUris you can define the uri for the figure.