3 min. reading time

In this post I show how to (ab)use PlantUML to visualize Xtext models. Warning: This is about diagrams, not about UML.

PlantUML Intro

PlantUML is an “Open Source tool [...] to draw UML using a simple and intuitive language”.
Let me just draw an example class diagram to demonstrate how it feels:
The following PlantUML specification

@startuml
abstract class Superclass << general >>;
abstract AbstractCreator{
  {abstract} create() : Superclass
}
Superclass <|-- Subclass
note left of Superclass : Instantiation not possible 
ConcreteCreator-up-|> AbstractCreator 
ConcreteCreator : create() : Superclass
ConcreteCreator .> Subclass
@enduml

results in this diagram:

plantumlex1.png

PlantUML also provides an Eclipse plugin which dynamically visualizes the “current active diagram, i.e. the diagram where the text cursor is located”. Better than that, this plugin provides an extension which lets you contribute a diagramTextProvider for a given editor. This means you can specify custom visualizations (limited by the PlantUML’s “UML”-capabilities) for any editor input. And the best of it: It works dynamically, i.e. while typing.

Create Xtext Project

Create a new Xtext Project (accept all defaults).  Adjust the grammar to make it look like this

// dont adjust grammar header
Model: greetings+=Greeting*;
Greeting: from=ID 'says' message=STRING 'to' to=ID;

and run the GenerateMyDsl.mwe2-worklow.

Create diagramTextProvider

Navigate to the ui project of your language. Add a dependency to the PlantUML-plugin to the MANIFEST.MF:

Require-Bundle: ...,net.sourceforge.plantuml.eclipse;

In the plugin.xml, add the following extension point:

<extension point="net.sourceforge.plantuml.eclipse.diagramTextProvider">
   <diagramTextProvider
   fileExtensions="mydsl"
        providerClass="org.xtext.example.mydsl.ui.plantuml.MyDiagramTextProvider">
   </diagramTextProvider>
</extension>

Implement MyDiagramTextProvider as follows:

class MyDiagramTextProvider extends AbstractDiagramTextProvider {
     
    def DomainmodelDiagramTextProvider() {
        fileExtensions = "mydsl";
        editorType = typeof(XtextEditor)
    }
     
    override String getDiagramText(IEditorPart editorPart, IEditorInput editorInput) {
        // Retrieve the "semantic" EMF from XtextEditor
        val document = (editorPart as XtextEditor).getDocumentProvider().getDocument(editorInput) as XtextDocument;
        val Model model = document.readOnly[
            return contents.head as Model
        ]
         
        // Collect names specified in textual model into Set
        val allNames = new HashSet 
        model.greetings.forEach[if(from!=null) allNames.add(from); if(to!=null) allNames.add(to)]
         
        // draw some actors and labelled arrows
        '''
            actor «FOR n:allNames»:«n»: as «n»
            «ENDFOR»
            «FOR it:model.greetings.filter[from!=null && to!=null && message!=null]»
                «from»->«to»:«message»
            «ENDFOR»
        '''
    }
}

Some notes on this implementation:

  • Apparently, this is an Xtend class.
  • I did not implement DiagramTextProvider directly. Instead, I extended AbstractDiagramTextProvider which comes with a lot of boilerplate code.

Try it

Run the Xtext/PlantUML plugins. It looks like (note: the editor is dirty … it really works dynamically):

Comments