Loading...

December 6, 2016

PlantUML Pleasantness: Create A Sudoku :)

PlantUML has a fun command to create a Sudoku puzzle. We must use sudoku in our PlantUML definition and a random puzzle is generated. We can even give a seed value for a given Sudoku so it is generated again.

In the following example PlantUML definition we use the sudoku command:

@startuml
sudoku
@enduml

We create a PNG file with PlantUML and we get the following result:

To regenerate the same Sudoku we must use the seed value cinnld556e0o:

@startuml
sudoku cinnld556e0o
@enduml

Written with PlantUML 8086.

PlantUML Pleasantness: Include Partial Content From Files

With PlantUML we can include external files in our definition with the !include directive. We specify the file name and the content is included in our PlantUML definition. The included file can also have multiple @startuml ... @enduml sections and we can refer to individual sections with the !include directive. We must append to the include file name an exclamation mark (!) followed by either a number or identifier. If we use a number we specify which section we want to include, where section are numbered starting from 0. So to get the second section from a file commons.puml we would write !include commons.puml!1. Alternatively we can use identifiers in the include file. We append to @startuml an identifier as (id=idValue). Then from the definition that is including the file we refer to the identifier after an exclamation mark (!). If our included file commons.puml has a section with id user then we would include it as !include commons.puml!user.

In the following example PlantUML definition we define the file to be included. We have two sections with @startuml ... @enduml which both have an identifier:

' File: commons.puml

' section with id user to define user actor
@startuml(id=user)
actor "Application User" as User
@enduml

' section with id mail to define mail component
@startuml(id=mail)
[Mail server] as Mail <<Mail>> #ffcc66
@enduml

Next we write a definition where we include commons.puml using a section number and section identifier:

' File: sample.puml
@startuml

' Include first section (0-based index) of commons.puml
!include commons.puml!0

' Include section with id mail of commons.puml
!include commons.puml!mail


[Sample Application] <<Software System>> as SampleApp

User --> SampleApp
SampleApp --> Mail

@enduml

Let's generate a diagram and look at the result where we see our user and mail components from the included file:

Written with PlantUML 8086.

PlantUML Pleasantness: Customize Stereotype Styling

To change the styling of our generated diagrams with PlantUML we can use the skinparam command. We can set for example font size, style, color, background colors and much more. We can change the style for a specific element or for the whole diagram. We can even set specific styling options for stereotypes. The settings for the stereotype are then applied to all elements in our diagram with that stereotype. We must append <<stereotype name>> to the skin parameter name.

In the following example PlantUML description we apply custom background colors to each stereotype:

@startuml

/' Set custom background colors for the default
   component elements and the specific stereotypes. '/
skinparam component {
    BackgroundColor #ff6666
    BackgroundColor<<Database>> #ccff66
    BackgroundColor<<Spring service>> #66ccff
    BackgroundColor<<Spring REST controllers>> #66ffcc
    BackgroundColor<<Spring repository>> #66ffff
    BackgroundColor<<Mail server>> #ffcc66
}

actor User
[Third party application] as ThirdPartyApp

together {
    [PostgreSQL database] as PostgresDB <<Database>>
    [Mail server] as Mail <<Mail server>>
}

package "Spring Boot Application" {
    [APIController] <<Spring REST controllers>>
    [AdminController] <<Spring REST controllers>>

    [AdminService] <<Spring service>>
    [DataStoreService] <<Spring service>>

    [Repository] <<Spring repository>>
}

User --> AdminController
ThirdPartyApp --> APIController

APIController --> DataStoreService
AdminController --> DataStoreService
AdminController --> AdminService

DataStoreService --> Repository
AdminService --> Mail

Repository --> PostgresDB

@enduml

When we generate the diagram we see that each stereotype has it's own background color:

Written with PlantUML 8086.

December 5, 2016

PlantUML Pleasantness: Keeping Elements Together

When we write a PlantUML definition the generated graphical diagram is laid out by PlantUML. In a previous post we learned how to move elements using the length of the connection. But we can also use a together block with all elements that should be at the same level. PlantUML will try to keep the elements together when the diagram is drawn.

In the following sample PlantUML definition we want the PostgresDB and Mail elements to be at the same level, so we group them using a together block:

@startuml

actor User
[Third party application] as ThirdPartyApp

/' Try to keep PostgresDB and Mail together,
   so they are at the same level in the diagram. '/
together {
    [PostgreSQL database] as PostgresDB <<Database>>
    [Mail server] as Mail <<Mail server>>
}

package "Spring Boot Application" {
    [Controllers] <<Spring REST controllers>>
    [DataStoreService] <<Spring service>>
    [Repository] <<Spring repository>>
}

User --> Controllers
ThirdPartyApp --> Controllers

Controllers --> DataStoreService

DataStoreService --> Repository
DataStoreService --> Mail

Repository --> PostgresDB

@enduml

Let's create the diagram and we see the elements are aligned nicely:

Written with PlantUML 8086.

PlantUML Pleasantness: No Shadows In Diagrams

By default elements in a PlantUML generated diagram have shadows. To disable shadows we must set the skin parameter shadowing to the value false. PlantUML will then not create shadows on elements.

In the following sample PlantUML definition we use the value false for the skin parameter shadowing:

@startuml

' Remove shadows
skinparam shadowing false

actor User
[Third party application] as ThirdPartyApp

package "Spring Boot Application" {
    rectangle Controllers <<Spring REST controllers>>
    rectangle DataStoreService <<Spring service>>
    rectangle Repository <<Spring repository>>
}

User --> Controllers
ThirdPartyApp --> Controllers

Controllers --> DataStoreService
DataStoreService --> Repository

@enduml

The generated diagram has no shadows:

Written with PlantUML 8086.

PlantUML Pleasantness: Diagrams In Black And White

The default colors of PlantUML use red and yellow to draw the diagram elements. If we want our diagram to be in black, grey and white we can simply set skin parameter monochrome to true. The generated graphical diagram will now have black, grey and white colors.

In the following sample PlantUML definition we set the diagram skin parameter monochrone to true:

@startuml

' Generated diagram will be in black/grey/white.
skinparam monochrome true

actor User
[Third party application] as ThirdPartyApp

package "Spring Boot Application" {
    rectangle Controllers <<Spring REST controllers>>
    rectangle DataStoreService <<Spring service>>
    rectangle Repository <<Spring repository>>
}

User --> Controllers
ThirdPartyApp --> Controllers

Controllers --> DataStoreService
DataStoreService --> Repository

@enduml

The generated diagram looks like this:

Written with PlantUML 8086.

PlantUML Pleasantness: Align Elements With Line Length

Drawing diagrams with PlantUML is fun and easy. We use text to describe the diagram and the we get a graphical representation. Especially in combination with Asciidoctor with PlantUML integration we have a winning combination to write technical documentation. Because our text is transformed into a graphical format like PNG we don't have much influence on the layout. There are options to indicate positions of elements, but we can also use the length of lines to influence the position of elements.

In the following sample we have a PlantUML diagram description with standard lines. We use two hyphens (--) to define a line:

@startuml
actor User
[Third party application] as ThirdPartyApp

[PostgreSQL database] <<Database>> as PostgresDB
[Mail server] <<Mail server>> as Mail

package "Spring Boot Application" {
    [Controllers] <<Spring REST controllers>>
    [DataStoreService] <<Spring service>>
    [Repository] <<Spring repository>>
}

User --> Controllers
ThirdPartyApp --> Controllers

Controllers --> DataStoreService
DataStoreService --> Repository

DataStoreService --> Mail

Repository --> PostgresDB
@enduml

We create a diagram and we get the following graphical diagram:

The diagram looks fine, but we want to have our mail server at the same level as the PostgreSQL database element. We simply add an extra hyphen (-) to the connection line between DataStoreService and Mail:

@startuml
actor User
[Third party application] as ThirdPartyApp

[PostgreSQL database] <<Database>> as PostgresDB
[Mail server] <<Mail server>> as Mail

package "Spring Boot Application" {
    [Controllers] <<Spring REST controllers>>
    [DataStoreService] <<Spring service>>
    [Repository] <<Spring repository>>
}

User --> Controllers
ThirdPartyApp --> Controllers

Controllers --> DataStoreService
DataStoreService --> Repository

/'Add extra hyphen (-) to put Mail
  add the same level as PostgresDB '/
DataStoreService ---> Mail

Repository --> PostgresDB
@enduml

We regenerate our diagram and we get the following result:

Written with PlantUML 8048.

November 23, 2016

Gradle Goodness: Delegate Build And Run Actions To Gradle In IntelliJ IDEA

IntelliJ IDEA 2016.3 introduces the option to delegate the IDE build and run actions to Gradle. So if we invoke the Build Project action from the Build menu IntelliJ IDEA invokes the correct tasks using Gradle. Also the Run and Debug actions from the Run menu are executed with Gradle.

If we want this behaviour we need to changed the preferences of IntelliJ IDEA. We must open the preferences dialog window and then go to Build, Execution, Deployment | Build Tools | Gradle | Runner. Here we check the option Delegate IDE build/run actions to gradle and we close the window:


Let's open a simple Java project with a Gradle build file in IDEA. Next we invoke the Build Project action with the shortcut key Cmd+F9 (on macOS, other operating systems probably have a different shortcut key). Our code is compiled and we can open the Run view to see the output:


We have a Java class in our project with a main method we want to run. We use the Run action (for example using the shortcut key Ctrl+R on macOS) and IDEA uses Gradle's JavaExec task to run the class. Also this time we can see the output in the Run view:


Written with Gradle 3.2 and IntelliJ IDEA 2016.3.

Gails Goodness: Enabling Grails View In IntelliJ IDEA For Grails 3

IntelliJ IDEA 2016.3 re-introduced the Grails view for Grails 3 applications. Grails 2 applications already were supported with a Grails view in IDEA. Using this view we get an overview of all the Grails artifacts like controller, services, views and more. We can easily navigate to the the class files we need. Now this view is also available for Grails 3 applications.

To enable the view we must click on the view selector in the project view:


We select the Grails option and we get an nice overview of our Grails project in the Grails view:


Also the New action is context sensitive in the Grails view. If we right click on the Services node we can see the option to create a new service class:


If we right click on the root node we get the option to create Grails artifacts:


Written with IntelliJ IDEA 2016.3 and Grails 3.2.2.

November 21, 2016

Gradle Goodness: Creation Rules For Rule Based Model Configuration Using Model DSL

In a previous post we learned how to create a class that extends RuleSource with methods that define rules on how to create and change objects in the Gradle model space. With the model configuration block in a build file we can also define creation rules for Rule based model configuration.

In the following build file we define a model block and define a creation rule for creating the object versionInfo of type VersionFile. Also we add a new task to the tasks object of type ModelMap<Task>. To reference another object from the model space inside the Closure for a creation rule we use the syntax $.<objectName>:

// File: model.gradle
import mrhaki.gradle.VersionFile
import mrhaki.gradle.VersionFileTask

model {
    // Creation rule to create object
    // with name versionInfo (name of the method)
    // and type VersionFile.
    versionInfo(VersionFile) {
        // Set default value for version to project.version.
        version = project.version
        
        // Set default outputFile to 
        // file version.txt in build directory.
        outputFile = project.file("${buildDir}/version.txt")
    }
    
    // tasks is of type ModelMap<Task>.
    tasks {
        // Create task generationVersionFile 
        // with custom task type VersionFileTask.
        create('generateVersionFile', VersionFileTask) {
            // Set properties with values
            // from managed object versionInfo,
            // that we created with the creation rule
            // versionInfo(VersionFile).
            // We use the special $.<name> notation
            // to reference object from the model space.
            version = $.versionInfo.version
            outputFile = $.versionInfo.outputFile
        }
    }
}

The supporting VersionFile class is a Gradle managed object:

// File: buildSrc/src/main/groovy/mrhaki/gradle/VersionFile.groovy
package mrhaki.gradle

import org.gradle.model.Managed

@Managed
interface VersionFile {
    String getVersion() 
    void setVersion(final String version) 

    File getOutputFile() 
    void setOutputFile(final File outputFile) 
}

And the custom task is very straight forward for our example:

// File: buildSrc/src/main/groovy/mrhaki/gradle/VersionFileTask.groovy
package mrhaki.gradle

import org.gradle.api.DefaultTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

/**
 * Simple task to save the value for the
 * {@link #version} property in a file.
 * The file is set with the {@link #outputFile}
 * property.
 */
class VersionFileTask extends DefaultTask {

    /**
     * Value for version to be saved.
     */
    @Input
    String version

    /**
     * Output file to store version value in.
     */
    @OutputFile
    File outputFile

    /**
     * Actual task actions to save the value
     * for {@link #version} in {@link #outputFile}.
     */
    @TaskAction
    void generateVersionFile() {
        outputFile.parentFile.mkdirs()
        outputFile.text = version
    }

}

We can use the model rules in our build script when we use apply from: 'model.gradle' in our build script. In our example we also add a model configuration block to configure the versionInfo object:

// File: build.gradle
apply from: 'model.gradle'

model {
    // Configuration rule for the versionInfo
    // object, that is created with the
    // creation rule from 'model.gradle'.
    versionInfo {
        version = '3.0.0.RELEASE'
    }   
}

Let's invoke the model task and check the output to see where are rules are applied:

$ gradle -q model
...
 tasks
      | Type:           org.gradle.model.ModelMap<org.gradle.api.Task>
      | Creator:        Project.<init>.tasks()
      | Rules:
         ⤷ tasks { ... } @ model.gradle line 18, column 5
...
    + generateVersionFile
          | Type:       mrhaki.gradle.VersionFileTask
          | Value:      task ':generateVersionFile'
          | Creator:    create(generateVersionFile, mrhaki.gradle.VersionFileTask) { ... } @ model.gradle line 21, column 9
          | Rules:
             ⤷ copyToTaskContainer
...
+ versionInfo
      | Type:           mrhaki.gradle.VersionFile
      | Creator:        versionInfo(mrhaki.gradle.VersionFile) { ... } @ model.gradle line 8, column 5
      | Rules:
         ⤷ versionInfo { ... } @ build.gradle line 47, column 5
    + outputFile
          | Type:       java.io.File
          | Value:      /Users/mrhaki/Projects/mrhaki.com/blog/posts/samples/gradle/versionrule/build/version.txt
          | Creator:    versionInfo(mrhaki.gradle.VersionFile) { ... } @ model.gradle line 8, column 5
    + version
          | Type:       java.lang.String
          | Value:      3.0.0.RELEASE
          | Creator:    versionInfo(mrhaki.gradle.VersionFile) { ... } @ model.gradle line 8, column 5
...
$

Written with Gradle 3.2.