JIRA PDF View Plugin: Scripting

Scripting

Prerequisites

Please study the basics of template development for the JIRA PDF View Plugin first, otherwise this tutorial will be more difficult to follow.

Why scripting?

The JIRA PDF View Plugin relies on Velocity as its primary language to define PDF document templates. In actual templates, Velocity logic statements are mixed with FO formatting tags to get the final result. Although Velocity is powerful at what it does, it is still purely a template language, not a full-blown programming language. That may impose limitations if you want to implement more complex PDF documents.

In many cases, this limitation is not a real problem as your documents may not require any complex logic. You just want to display some fields, do some formatting, make trivial if-then switches. To implement these, using Velocity alone is sufficient, and you should not complicate your life with scripting.

In other situations, the requirements for the logic that needs to be built into your templates are more complex than simple if-then statements or iterating over a collection of objects. To implement these, Velocity alone will not be enough, you will need to do some scripting.

Don't worry, scripting is easy and it opens new horizons for your PDF documents!

When to use scripting?

Some use case examples that you can implement only with scripting (not in Velocity alone):

  • Draw charts. (Ex: generate graphical visualization in project status reports.)
  • Integrate with external resources. (Ex: integrate vendor information into your quotes queried from an external CRM database or an external webservice.)
  • Do precise arithmetic. (Ex: calculate precise money values in invoice documents.)
  • Access JIRA internals. (Ex: execute a secondary saved filter to collect more data.)
  • Implement data processing algorithms using advanced data structures. (Ex: build dependency tables for traceability matrixes.)

What is Groovy?

Groovy is the primary scripting language supported by the JIRA PDF View Plugin. Groovy is agile scripting language for the Java platform, the same platform on which JIRA runs.

What are the advantages of Groovy, compared to other scripting languages?

  • It is very easy to learn and use.
  • It is already known for JIRA users, as many other JIRA plugins use Groovy to implement custom logic.
  • It beautifully integrates with JIRA internals.
  • There are lots of sample code, documentation and answers available on the web.
  • It is mature and proven, having been used in mission critical apps at large organizations for years.

How can I learn Groovy?

The basics of Groovy can be learnt literally in hours, assuming that you have some background in modern programming languages, like Java, Javascript or C++.

Useful resources:

Writing Groovy scripts

Your first script in 2 minutes

Here is the good old Hello world example, implemented with Groovy for the JIRA PDF View Plugin.

First, save your logic to a Groovy script file hello-world.groovy:

// hello-world.groovy

helloWorld = new HelloWorldTool()

class HelloWorldTool {
    def say() {
        "Hello world!"
    }
}

Then, execute it in your template hello-world-fo.vm:

## hello-world-fo.vm

## execute the script with the $scripting tool, depending on your plugin version

## in version 2.0.0 or newer, use simply the script's filename
$scripting.execute("hello-world.groovy")

## in versions prior to 2.0.0, use the path relative to the JIRA classpath
$scripting.execute("/templates/plugins/pdfview/hello-world.groovy")

## after executing the script, the object "$helloWorld" is available
## let's call a method and put the greeting text to a text block
<fo:block><fo:inline font-weight="bold">Ex 1:</fo:inline> $helloWorld.say()</fo:block>

Tadaam. That's it. Now you have a block in the PDF, containing the text generated by the Groovy code.

Tip: it is usually a good idea to follow the naming convention used above. If your template is an implementation of "my document type", then save the template code to my-document-type-fo.vm and the script to my-document-type.groovy. It helps to see what files belong together.

Passing objects from templates to scripts

Besides the basics of script execution, it is important to learn how to share and pass objects between template codes and scripts.

Scripts have a dead-simple way to access the Velocity context objects used in templates. There is an important aspect of script execution, which is albeit transparent, yet important to understand. Before execution, each script is converted to an actual Groovy class in the background. Our script hello-world.groovy will be converted to the class named hello-world, for instance. And then, the Velocity context objects will available as properties of that class. Because the generated class is the "outermost" class in the script, its properties appear like "global variables" (more on this later). Simple, right?

Here is an example. You probably know that the currently signed in JIRA user is available as $user in the template code. Also, this is available as the object user in Groovy!

// hello-world-fo.groovy

helloUser = new HelloUserTool(user) // "user" is available from the Velocity context

class HelloUserTool {
	def user

	HelloUserTool(user) {
		this.user = user // store the argument for later use
	}

	def say() {
		"Hello ${user.displayName}!" // use a property
	}

	def say2(issues) {
		"Hello ${user.displayName}! You have ${issues.size()} issues." // use a property and a method argument
	}
}

Let's greet him:

## hello-world-fo.vm

<fo:block><fo:inline font-weight="bold">Ex 2:</fo:inline> $helloUser.say()</fo:block>

You can also pass arguments to the Groovy methods with ease:

## hello-world-fo.vm

<fo:block><fo:inline font-weight="bold">Ex 3:</fo:inline> $helloUser.say2($issues)</fo:block>

The resulted PDF:

Final note: although from the above code it may feel like as if we had a global variable "user", this is not true. In fact, there is no such thing like "global" in Groovy! Read this article to avoid surprises.

Passing objects from scripts to templates

The recipe is simple: all so-called "binding variables" instantiated in Groovy will be automatically available in the templates.

What is a binding variable? When it is not defined, it is in the binding, thus it will be available in templates, too.

bindingVar = "I am a binding variable"
String localVar = "I am a local variable" // it will *not* be available in the template

Therefore, we recommend capturing your logic in lightweight classes, instantiating them as binding variables in Groovy and calling their methods in the template code. You may also want to follow the naming convention of calling your tool classes SomethingTool and instantiating them called something, just as we did in the examples.

Good practices

  1. Separation of concerns: clearly separate visuals and logic. Use Velocity for iterating, trivial if-then's, formatting, and use Groovy for implementing complex logic. Not vice versa!
  2. Follow the naming conventions suggested in this article.
  3. Turn off template caching for the time of the development. See item 4 in the plugin FAQ.

Advanced examples

Viewing the example templates shipped in the plugin distribution is a great way to study implementations of real life document types. (You can find the related files in the classes/templates/plugins/pdfview directory.)

Gantt charts

A Groovy script is used to compute the start- and end date of tasks, to calculate the spanned period and the geometry of the bars. Based on that, the template renders an appropriately sized table, where the cells simulate the sections of the task bars.

Files: gantt-chart-fo.vm, gantt-chart.groovy

Traceability matrixes

A simple Groovy script collects the dependencies defined by issue links into an efficient data structure. It uses a Table object (pairs of issues are mapped to their dependency) from the Google Guava library, so it also demonstrates using a 3rd party library in scripts. Then, the template iterates over the issues and renders a table by putting the dependency direction images to the cells.

Files: traceability-matrix-fo.vm, traceability-matrix.groovy

Recommended tools for scripting

If you are a purist (or don't have the time), you can actually do all your work with a simple text editor!

If you would like to enjoy syntax highlighting, code-completion and so, we recommend to use the Eclipse IDE (a great general purpose development environment) combined with the following plugins:

  1. Velocity UI to edit Velocity templates (*.vm).
  2. Groovy-Eclipse to edit Groovy scripts (*.groovy).

Questions?

Ask us any time.