This document describes how to use Groovy builder for the PlantUML language. The document is written in AsciiDoc.

Version history

Document version Notes Date Author

0.0.1

Initial Asciidoc version, updated
Realated to platnumlbuilder version 0.4.4

2015-06-21

Michal Novák

References

Terminology

License

The [plantumlbuilder] is free software, licensed under MIT License.

The plantumlbuilder is free software licensed under MIT License.

-----
Copyright (c) 2011-2012 Michal Novak (it.novakmi@gmail.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----

Introduction

Note
This document is still work in progress. Please take a look at the examples in the templates\scripts directory and at the tests in the tests\groovy directory to see usage of all [plantumlbuilder] features.

The [platnumlbuilder] represents implementation of [groovy] builder for [PlantUML] language.

Using groovy builders is a way to create tree like structures in source code. PlantUML language does not fully resemble tree like structure, in spite of this, a groovy builder can simplify UML modeling in PlantUML language (especially sequence diagrams).

The main benefits of using builder are:

  • reuse - in UML diagram and between UML diagrams

  • parametrization

  • customization of diagram language

  • direct creation of UML images from groovy script

  • taking advantage of an IDE (e.g. Intellij Idea) when creating UML diagram - text formatting, auto completion

Dependencies

To start using [plantumlbuilder] you need to have [PlantUML] jar file (plantuml.jar) and [plantumlbuilder] jar file (plantumlbuilder-x.x.x.jar) or sources. For editing it is recommended to use [[http://www.jetbrains.com/idea/| Intellij Idea IDE]] (e.g. free community edition) to create UML in [groovy].

First Plantumlbuilder diagrams

The basic [plantumlbuilder] command is plant element. See following groovy script:

// create new builder
def builder = new PlantUmlBuilder()
// plantuml element is a root element of PlantUML
builder.plantuml {
            plant('A->B') // plant  only puts text to the output
            plant('activate B')
            plant('B->C')
            plant('activate C')
            plant('C-->B')
            plant('deactivate C')
            plant('A-->B')
            plant('deactivate B')
}

println builder.getText() // get PlantUML text
println ''
println 'Without @startuml/@enduml'
println builder.getText(plainPlantUml: true)  // get PlantUML text without @startuml and @enduml

// use plantUML to create png file from plantuml text
SourceStringReader s = new SourceStringReader(builder.getText())
FileOutputStream file = new FileOutputStream('./example1.png')
s.generateImage(file)
file.close()

This produces following [PlantUML] output (and image file):

@startuml
A->B
activate B
B->C
activate C
C-->B
deactivate C
A-->B
deactivate B
@enduml

Without @startuml/@enduml
A->B
activate B
B->C
activate C
C-->B
deactivate C
A-->B
deactivate B

As you can see, it is possible to generate either PlantUML text enclosed in @startuml/@enduml (builder.getText()) or text not being enclosed in @startuml/@enduml (builder.getText(plainPlantUml: true)). The latter is useful for example if you want to add image name to the [PlantUML] text.

Next script (only <<plantumlbuilder> part shown) produces same diagram picture, but the output is differently indented.

Note
Note you can use builder.reset() to clear already existing content of the builder.

Another example with reuse (closure).

builder.reset()
final def A = 'A'
final def B = 'B'
final def C = 'C'

builder.plantuml() {
        // example of block reuse
        def interact = {a, b ->
                plant "$a->$b"
                plant "activate $b"
                plant "$b-->$a"
                plant "deactivate $b"
        }
        title 'Plantuml builder basic template - simple sequence diagram'
        plant 'participant "A node" as A'
        plant "participant B"
        plant "participant C"
        plant "$A->$B"
        plant "activate $B", {
                interact(B, C) //reuse
        }
        plant "$B-->$A"
        plant "deactivate $B"
        interact(C, B) //reuse
}

Following PlantUML text is created:

@startuml
title Plantuml builder basic template - simple sequence diagram
participant "A node" as A
participant B
participant C
A->B
activate B
  B->C
  activate C
  C-->B
  deactivate C
B-->A
deactivate B
C->B
activate B
B-->C
deactivate B
@enduml
Note
You can see the indenting of the text follows parent/child relationship of builder elements. This is useful (for more complex diagrams) to increase readability.
Note
The syntax follows groovy builder syntax, and one can also use bracket, e.g.: plant("participant C") or plant("activate $B") {...

Advanced diagram example

The possibility to use programming language to create diagrams is not the only advantage. With Plugins, one can made custom syntax for specific diagrams or domain. Together with the [plantumlbuilder] there comes plugins for different types of UML diagrams.

Following example demonstrates how [plantumlbuilder] can be used together with PlatnUmlBuilderSeqPlugin for sequence diagrams parts of sequence diagram.

def u1 = 'User1'
def m1 = 'MobileA'
def m2 = 'MobileB'
def u2 = 'User2'

builder.plantuml() {
        title 'Plantuml builder seq plugin template example with activation colors and boxes'

        box {
                actor u1
        }
        box "Mobile", {
                participant m1
        }
        box("Mobile", color: "#LightBlue") {
                participant m2
        }
        box color: "#green", {
                actor u2
        }

        msgAd u1, to: m1, text: "Start Call", returnText: "Call finished", {
                msg m1, to: m2, text: "Ring", noReturn: true
                msgAd u2, to: m2, activate: "#FFBBBB", text: "PickUp", returnText: "HangUp", {
                        msgAd m2, to: m1, activate: "#yellow", text: "Talk"
                }
        }
}

Following PlantUML text is created

@startuml
title Plantuml builder seq plugin template example with activation colors and boxes
box
  actor User1
end box
box "Mobile"
  participant MobileA
end box
box "Mobile" #LightBlue
  participant MobileB
end box
box #green
  actor User2
end box
User1 -> MobileA : Start Call
activate MobileA
  MobileA -> MobileB : Ring
  User2 -> MobileB : PickUp
  activate MobileB #FFBBBB
    MobileB -> MobileA : Talk
    activate MobileA #yellow
    MobileA --> MobileB
    deactivate MobileA
  MobileB --> User2 : HangUp
  deactivate MobileB
MobileA --> User1 : Call finished
deactivate MobileA
@enduml

[plantumlbuilder] language reference

Base reference

Following keywords can be used by the [plantumlbuilder].

plantuml

Represents [plantumlbuilder] root node mark (not present in PlantUML text). It is possible to pass text to be placed after @startuml (e.g. image name).

Examples:

[plantumlbuilder] PlantUML
builder.plantuml {
...
}

N/A

builder.plantuml("img\myuml.png") {
...
}

N/A

plant

Text is directly copied as line to the PlantUML text. With this keyword,any PlantUML keyword can be entered by the builder.

Example(s):

[plantumlbuilder] PlantUML
plant("autonumber")
autonumber

Example(s):

[plantumlbuilder] PlantUML
title("My diagram")
title My diagram
footer('''My footer
        multiline''')
footer
   My footer
   multiline
end footer
Note
Use groovy multiline string or \n to create multiline elements. Multiline elements are automatically trimmed and indented.
Note
Use \\n in the groovy string to format one line element on the several lines

legend

Attributes: pos (optional) - left, center and right

Example(s):

[plantumlbuilder] PlantUML
legend("My legend")
legend
   My legend
end legend
legend('''My legend
        multiline''', pos: "right")
legend right
   My legend
   multiline
end legend
Note
Use groovy multiline string or \n to create multiline legends. Multiline legends are automatically trimmed and indented.
Note
Use \\n in the groovy string to format one line legend on the several lines

newpage

Example(s):

[plantumlbuilder] PlantUML
newpage()
newpage
newpage "Page break"
newpage Page break
newpage "Page break\\nmore lines"
newpage Page break\nmore lines

note

Attribute: as (optional), pos (optional)

Example(s):

[plantumlbuilder] PlantUML
note("MyNote")
note MyNote
note("My note", as: "MyNote")
note My note as MyNote
note("MyNote", pos: "right")
note right : MyNote
 note ('''a note
            can also be defined
         on several lines  ''', pos: "left of A", color: "blue")
note left of A #blue
  a note
  can also be defined
  on several lines
end note
Note
Use groovy multiline string or \n to create multiline notes. Multiline notes are automatically trimmed and indented.
Note
Use \\n in the groovy string to format one line note on the several lines

Plugins

Plantumlbuilder sequence plugin

See PlantUmlBuilderSeqPluginTest for more information and examples.

Following keywords are supported (added) by the sequence plugin.

participant, actor, boundary, control, entity and database

Attributes: as (optional) color (optional) stereotype (optional)

Example(s):

[plantumlbuilder] PlantUML
participant("MyParticipant")
participant MyParticipant
participant("My Participant", as: "MyParticipant")
participant My Participant as MyParticipant
participant("MyParticipant", color: "#red")
participant MyParticipant #red
actor("MyActor")
actor MyActor
actor("My Actor", as: "MyActor", stereotype: "person")
actor "My Actor" as MyActor <<person>>
Note
In similar way use boundary, control, entity and database NOTE: If value contains space character (e.g. "My actor"), it is automatically surrounded by the quotes ", unless there are surrounding quotes already present in the value (e.g. '"My actor"' or "\"My actor\"")

create

Attributes: type (optional) - one of participant, actor, boundary, control, entity and database (default is participant) as (optional) color (optional) stereotype (optional)

[plantumlbuilder] PlantUML
create "MyParticipant"
create MyParticipant
create "My Participant", as: "MyParticipant"
create "My Participant" as MyParticipant
create "MyParticipant", type: "control", color: "#red")
create control MyParticipant #red
crreate "My Actor", as: "MyActor", stereotype: "person", type: "actor"
create actor "My Actor" as MyActor <<person>>
Note
If value contains space character (e.g. "My actor"), it is automatically surrounded by the quotes ", unless there are surrounding quotes already present in the value (e.g. '"My actor"' or "\"My actor\"")

msg

Sequence diagram message.

Attributes (all optional):

  • to (string - existing actor, participant, etc.)

  • noReturn (boolean)

  • text (string)

  • returnText (string)

  • type (string)

  • returnType (string)

  • activate (boolean or string - activation color)

  • close (string - "activate" or "destroy")

[plantumlbuilder] PlantUML Note
msg("A")
A -> A

Create a message with self arrow.

msg("A", to: "B") {
...
}
A -> B
...
B --> A

Create message from A to B with automatic return arrow from B to A

msg("A", to: "B", noReturn:true)
A -> B

Create message from A to B without return arrow

msg("A", to: "B", text:"call B") {
...
}
A -> B : call B
...
B --> A

Create message from A to B with arrow text

msg("A", to: "B", type: "-->") {
...
}
A --> B
...
B --> A

Create message from A to B with different arrow type (same as return arrow)

msg("A", to: "B", activate: "true") {
...
}
A -> B : call B
activate B
...
B --> A

Create message from A to B with activation of the second participant

msg("A", to: "B", text:"call B", close: "deactivate") {
...
}
msg("A", to: "B", text:"call B", close: "destroy") {
...
}
A -> B : call B
activate B
...
B --> A
deactivate B
A -> B : call B
activate B
...
B --> A
destroy B

Create message from A to B with activation (automatic) nad deactivation or destroy of the second participant

msg("A", to: "B", returnText: "finished") {
...
}
A -> B
...
B --> A : finished

Create message from A to B with return arrow text

msg("A", to: "B", returnType: "->") {
...
}
A -> B : call B
...
B -> A

Create message from A to B with different return arrow type

Note
Incoming and Outcoming messages are also supported with use of [ and ]. For example msg("[", to: "A") or msg("]", to: "A", text: "o2")

msgAd

This keyword has same meaning as the msg keyword. In addition, it automatically adds close attribute with the deactivate value (can be overwritten with the destroy value).

msgAd("A", to: "B") {
...
}

is same as:

msg("A", to: "B", close: "deactivate") {
...
}

destroy can be specified by adding close attribute (in this case msg and msgAd are same)

msgAd("A", to: "B", close: "destroy") {
...
}

is same as:

msg("A", to: "B", close: "destroy") {
...
}

The activation color can be specified with activate attribute:

msgAd("A", to: "B", activate: "#Green") {
...
}

is same as:

msg("A", to: "B", activate: "#Green", close: "deactivate") {
...
}

activate

Attribute: close (optional) - specifies how to close the activation block, value can be deactivate or destroy

Activate participant. With attribute close it is possible to specify activate - deactivate or activate - destroy block.

[plantumlbuilder] PlantUML
activate("A")
activate A
activate("A", close: "deactivate") {
...
}
activate A
...
deactivate A
activate("A", close: "destroy") {
...
}
activate A
...
destroy A

deactivate and destroy

Deactivate or destroy the participant.

[plantumlbuilder] PlantUML
deactivate("A")
deactivate A
destroy("A")
destroy A

autonumber

Specify arrow numbering

value: numbering start (optional)

Attributes:

step: numbering step format: numbering format

[plantumlbuilder] PlantUML
autonumber()
autonumber
autonumber 15
autonumber 15
autonumber 40 15
autonumber 40 15
autonumber format: "<b>[000]"
autonumber "<b>[000]"
autonumber 40, step: 10, format: "<font color=red><b>Message 0"
autonumber 40 10 "<font color=red><b>Message 0"

divider

Create divider of given name

[plantumlbuilder] PlantUML
divider("separate")
== separate ==

delay

Create delay of given name

[plantumlbuilder] PlantUML
delay("wait")
...wait...

group

Create group of given name

[plantumlbuilder] PlantUML
group("MyGroup") {
...
}
group MyGroup
...
end

opt

Create opt frame for given condition

[plantumlbuilder] PlantUML
opt("condition") {
...
}
opt condition
...
end

alt and else

Create alt frame for given condition with else

[plantumlbuilder] PlantUML
alt("condition1") {
...
  else("condition2")
...
}
alt condition1
...
else condition2
...
end
Note
else in the groovy code is inside the alt block

loop

Create loop frame for given loop condition

[plantumlbuilder] PlantUML
loop("condition") {
...
}
loop condition
...
end

par

Create par frame

[plantumlbuilder] PlantUML
par("in parallel") {
...
}
par in parallel
...
end

break

Create break frame

[plantumlbuilder] PlantUML
"break"("MyBreak") {
...
}
break MyBreak
...
end
Note
As break is [groovy] keyword, in the builder it has to be specified as string

critical

Create critical frame

[plantumlbuilder] PlantUML
critical("MyCritical") {
...
}
break MyCritical
...
end

ref

Create ref frame

Attribute: over - list of participants (mandatory)

[plantumlbuilder] PlantUML
ref("see diagram X", over: ["A", "B"])
ref over A,B: see diagram X
Note
Currently only one line ref is supported. Multiline ref has to be created with the plant keyword.

box

Encompass participants in the box

Attribute: color - the color of the box

[plantumlbuilder] PlantUML
box("User") {
    actor("user")
}
box User
   actor user
end box
box("User", color: "#LightBlue") {
    actor("user")
}
box User #LightBlue
   actor user
end box

hnote and rnote

Hexagon and rectangle note for sequence diagrams.

Attribute: pos (mandatory) color

Example(s):

[plantumlbuilder] PlantUML
hnote("MyHNote", pos: "over A")
hnote over A : MyHNote
rnote("MyRNote", pos: "over A")
rnote over A : MyRNote
hnote("See\\nthis diagram", pos: "over A")
rnote over A : See\nthis diagram
hnote("See\\nthis diagram", pos: "over A", color: "green")
rnote over A #green : See\nthis diagram
Note
hnote nad rnote support multiline handling just like regular note

Plantumlbuilder class plugin

See PlantUmlBuilderClassPluginTest for more information and examples.

TODO

Plantumlbuilder component plugin

See PlantUmlBuilderCompPluginTest for more information and examples.

TODO

Interface

Plantumlbuilder groovy interface

The interface consists of two parts

  • the Plantumlbuilder interface

  • the Plugin interface allowing extension of Plantumlbuilder language

    TODO

    images/plantbuilderinterface.png

PlantUmlBuilder interface

/**
 * Get PlantUML text build by the builder
 * @param params map with optional name params.
 *         Currently supported 'plainPlantUml' - do not add '@startuml/@enduml' to the returned PlantUML text
 *         getText()
 *         getText(plainPlantUml: true)
 * @return build text
 */
public String getText(params)
/**
 * Reset root element of the builder.
 * Use this method to start building PlantUML text from the beginning.
 */
public void reset()
/**
 * Add a plugin listener.
 */
void addPlantUmlBuilderPluginListener(PlantUmlBuilderPluginListener listener)
/**
 * Remove the plugin listener.
 */
void removePlantUmlBuilderPluginListener(PlantUmlBuilderPluginListener listener)
TODO

See {{{cz.atlas.bubbles.it.test.plantumlbuilder.PlantUmlBuilderTest}}} for examples of the usage.

PlantUmlBuilderPluginListener interface

/**
 * Builder node
 */
private class Node {
    def name = ''   // name of node (e.g. plant('text, at:'attrib') - name is plant)
    def parent = null // parent node (or null if this is root node)
    def attributes = [:] //attributes (e.g. plant('text, at:'attrib') - attributes.at == 'attrib')
    def value = null //value of node (e.g. plant('text, at:'attrib') - value is text)
    def children = [] //children nodes
}
//Listener interface  for node or attributes
enum PluginListenerResult {
    NOT_ACCEPTED, // node not accepted by the  plugin
    PROCESSED_STOP, // node processed by the plugin, do not process node with other plugins
    PROCESSED_CONTINUE, // node processed by plugin, process node with other plugins as well
    FAILED, // node processing failed
}
interface PlantUmlBuilderPluginListener {
    /**
     * Process given node in plugin before and after plantuml builder
     * @param node builder node to process (
     * @param out IndentPrinter to print PlantUML text
     * @param postProcess if false, it is pre processing time, if true, it is post processing time
     * @return result
     * $see PluginListenerResult, Node
     */
    PluginListenerResult process(final Node node, IndentPrinter out, boolean postProcess)
}

Plantuml Maven repository

The [plantumlbuilder] has been accepted by JCenter and is available in the JCenter Maven repository. It can be automatically used with Groovy @Grab or in the gradle. There is no need to download and maintain jar files.