To extract an interface from a UML class using the GMF-based UML2Tools class-diagram editor, one has to manually go through the following steps:
- create and name the new interface
- move the methods from the concrete class to the interface
- create a generalization between the class and the interface
- update all association ends that pointed to the class to now point to the interface
Having a wizard that could do all the above with a single click instead would arguably be a good thing. Even more, having a tool that would allow us to easily define custom wizards at a high level of abstraction by hiding the complexity of GMF would be even better.
Motivated by such scenarios, in the Epsilon GMT component we have implemented a small dedicated language (EWL) and supporting tools that enable users to specify and execute such wizards from within GMF-based editors. Our solution works with existing editors, such as the UML editors provided by the UML2Tools project, without needing to customize or re-generate them. Wizards appear in a sub-menu of the right-click menu and their effects can be undone/redone using the standard Ctrl-Z/Ctrl-Y shortcuts. Wizards are also interactive in the sense that they can prompt the user to provide additional information through standard Eclipse dialogs.
This screencast demonstrates defining and executing a wizard that implements the scenario above, as well as undoing/redoing its effects on the model. A detailed discussion on EWL can be found here and an overview of the GMF/EWL integration can be found here.
Cool! I could imagine it being used to create an “association” based on a pattern like the one I described in http://ed-merks.blogspot.com/2008/01/modeling-associations-with-ecore.html .I guess it could work in either the Ecore Tools graphical editor or even in the sample one…
Thanks. I actually tried it with the built-in GMF ECore visual editor. The EWL wizard that creates the first type of association class looks like this:
wizard CreateAssociationClassCase1 {
guard : self.isKindOf(Collection) and
self.size() = 2 and self.forAll(s|s.isTypeOf(ecore::EClass))
title : ‘Create association ‘ + self.at(0).name + self.at(1).name + ‘Link’
do {
var classA := self.at(0);
var classB := self.at(1);
var classABLink := new ecore::EClass;
classABLink.name := classA.name + classB.name + ‘Link’;
classA.ePackage.eClassifiers.add(classABLink);
var classARefB := classA.createRef(classB, true);
var classBRefA := classB.createRef(classA, true);
var classABLinkRefA := classABLink.createRef(classA, false);
var classABLinkRefB := classABLink.createRef(classB, false);
var classARefABLinks := classA.createRef(classABLink, true);
var classBRefABLinks := classB.createRef(classABLink, true);
classARefABLinks.eOpposite := classABLinkRefA;
classBRefABLinks.eOpposite := classABLinkRefB;
classABLinkRefA.eOpposite := classARefABLinks;
classABLinkRefB.eOpposite := classBRefABLinks;
classARefABLinks.containment := true;
}
}
operation ecore::EClass createRef(type : ecore::EClass, many : Boolean) : ecore::EReference {
var ref := new ecore::EReference;
ref.name := type.name.firstToLowerCase();
if (many) {ref.name := ref.name + ‘s’;}
self.eStructuralFeatures.add(ref);
ref.eType := type;
if (many) {ref.upperBound := -1;}
return ref;
}
That’s very succinct! Cool.
BTW, why doesn’t http://www.eclipse.org/modeling/project-info/team.php have a nice photo of you and a biography? Please reopen https://bugs.eclipse.org/bugs/show_bug.cgi?id=182613 and provide some details about yourself.
Thanks Ed. I’ll do that asap.
Pingback: Model Refactoring in EMF editors « Epsilon Weblog