Writing a Velocity report step by step

By Jason posted 01-07-2016 17:14

  
Note that user-created Velocity reports can be uploaded to on-premises versions of Jama only. Hosted customers need to follow the instructions here to have their reports uploaded.
 
This is a guide to writing Velocity reports in Jama. It demonstrates starting with a basic template and building the report through multiple iterations, making small changes at each step so that it is easy to see what worked and what did not. This shows a specific report as an example, but the workflow should apply to any report you want to write.

The report in this example shows the number of active items by type in each project in Jama. These examples were created in Jama 2015.2. To run any of the examples, save the example code in a text file named "itemcounts.vm." In Jama, go to Admin > Reports and add a report with the following settings:


To run the report, select a project and then Reports > Item Counts by Project > Run Report.

Step 1) Base template
Velocity reports are fundamentally just HTML markup, so start with a very basic layout.

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
</body>
</html>




 
 
 
Step 2) List Projects
First, the report needs to list available projects in Jama. In Jama's Velocity report documentation, the projectDao.getProjects() method returns a list of projects.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($projects = $projectDao.getProjects(true))

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
#foreach ($project in $projects)
$project.name<br>
#end

</body>
</html>


 
Background information:
What is "Dao"? What is "Bean" and why do I need to get one?
Velocity (and Jama) are written in the Java programming language. Think of a Data Access Object (DAO) as a helper that retrieves records stored in a database. Different DAOs would be used for different kinds of objects. For example, projectDao is used for projects, relationshipDao is used for relationships, and so on. 
 
A JavaBean is a Java class that follows certain conventions for naming and behavior.
$projectDao = $applicationContext.getBean("projectDao") basically says "get me a projectDao object and store it in the variable $projectDao." The variable name and bean type do not have to be the same, but it makes things less confusing!
 

 
Step 3) Show only actual projects
Some entries are showing up in the list twice, like "IIBA BABOK." In the Select Project window in Jama, projects can be arranged in Folders. The folders are the extra entries in the previous example. 


 
For this report, the folders are not needed, just a list of projects. To fix that, check to see if each project is a Folder, and only show it if it is not.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($projects = $projectDao.getProjects(true))

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
#foreach ($project in $projects)
#if (!$project.isFolder)
$project.name<br>
#end
#end
</body>
</html>


 
 

Step 4) Get item counts for each project
In Jama's Velocity documentation, contourIteamDao.getAllItemTypesCount() returns a map object, which is a list of name/value pairs. In this case, the name is the Item Type and the value is the number of items of that type in a project. 
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($contourItemDao = $applicationContext.getBean("contourItemDao"))
#set($projects = $projectDao.getProjects(true))

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
#foreach ($project in $projects)
#if (!$project.isFolder)
#set ($itemCounts = $contourItemDao.getAllItemTypesCount($project.id))

$project.name<br>
$itemCounts<br>
#end
#end
</body>
</html>



 
 
Step 5) Show each Item Type on its own line
Each Item Type should be on its own line. The Velocity User Guide has an example of how to get keys (names) and values out of a map object.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($contourItemDao = $applicationContext.getBean("contourItemDao"))
#set($projects = $projectDao.getProjects(true))

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
#foreach ($project in $projects)
#if (!$project.isFolder)
#set ($itemCounts = $contourItemDao.getAllItemTypesCount($project.id))

$project.name<br>
#foreach ($itemType in $itemCounts.keySet())
$itemType - $itemCounts.get($itemType)<br>
#end
#end
#end
</body>
</html>



 
 
Step 6) Display Item Type names instead of id numbers
That is a good start, but the report needs the name of the Item Type instead of just the ID number. In Jama's documentation, documentTypeDao.getAllDocumentTypesMap() returns a map object containing id/document type pairs in a given organization.
 
For each Item Type, get the name of the Item Type from the $documentTypes map, and the count from the $itemCounts map.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($contourItemDao = $applicationContext.getBean("contourItemDao"))
#set($documentTypeDao = $applicationContext.getBean("documentTypeDao"))
#set($projects = $projectDao.getProjects(true))
#set($documentTypes = $documentTypeDao.getAllDocumentTypesMap(2))

<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
#foreach ($project in $projects)
#if (!$project.isFolder)
#set ($itemCounts = $contourItemDao.getAllItemTypesCount($project.id))

$project.name<br>
#foreach ($itemType in $itemCounts.keySet())
$documentTypes.get($itemType) - $itemCounts.get($itemType)<br>
#end
#end
#end
</body>
</html>



Note: Another way to do this would be to make a documentTypeDao.getDocumentType() call for each document type in the report. In a short report, this probably would not make much difference. In a report with many projects and Item Types, it could be considerably faster to get all the document types at once.
 
 

Step 7) Add formatting
Now that all the data is in the report, change the page layout so each project is in its own row with the Item Types to the right.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($contourItemDao = $applicationContext.getBean("contourItemDao"))
#set($documentTypeDao = $applicationContext.getBean("documentTypeDao"))
#set($projects = $projectDao.getProjects(true))
#set($documentTypes = $documentTypeDao.getAllDocumentTypesMap(2))
<html>
<head>
<title>Item Counts by Type per Project</title>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
<table>
#foreach ($project in $projects)
#if (!$project.isFolder)
#set ($itemCounts = $contourItemDao.getAllItemTypesCount($project.id))
<tr>
<td>$project.name</td>
<td>
<table width="100%">
#foreach ($itemType in $itemCounts.keySet()) 
<tr>
<td>$documentTypes.get($itemType)</td>
<td>$itemCounts.get($itemType)</td>
</tr>
#end
</table>
</td>
</tr>
#end
#end
</body>
</html>



 

Step 8) Change font and fix alignment
Finally, change the font on the page, add formatting and fix the alignment in the tables.
 
#set($projectDao = $applicationContext.getBean("projectDao"))
#set($contourItemDao = $applicationContext.getBean("contourItemDao"))
#set($documentTypeDao = $applicationContext.getBean("documentTypeDao"))
#set($projects = $projectDao.getProjects(true))
#set($documentTypes = $documentTypeDao.getAllDocumentTypesMap(2))

<html>
<head>
<title>Item Counts by Type per Project</title>
<style>
body { font-family: sans-serif;}
h1 { font-size: 1.5em; text-align:right;}
</style>
</head>
<body>
<h1>Item Counts by Type per Project</h1>
<table>
#foreach ($project in $projects)
#if (!$project.isFolder)
#set ($itemCounts = $contourItemDao.getAllItemTypesCount($project.id))

<tr>
<td valign="top"><b>$project.name</b></td>
<td>
<table width="100%">
#foreach ($itemType in $itemCounts.keySet())
<tr>
<td align="left">$documentTypes.get($itemType)</td>
<td align="right">$itemCounts.get($itemType)</td>
</tr>
#end
</table>
</td>
</tr>
#end
#end
</body>
</html>



 
 
Troubleshooting

Problem: Velocity shows variable names instead of values in the report

For example: 
#set ($myText = "This is my text")
$myText
$otherText

​Displays:
This is my text
$otherText
If a variable or property does not exist, by default Velocity will print the variable's name instead. Often that is because a property does not exist on one type of item. For example, when iterating through all items in a project, a Requirement and a Test Case have different fields. 
 
Use a quiet reference to override that behavior by adding an exclamation point after the dollar sign. For example:
#set ($myText = "This is my text")
$!myText
$!otherText
 
Would display:
This is my text
 
Problem: When the report is run, the report just says "No results"
This usually indicates that there was a serious problem running the report. The specific error can usually be found in the Jama’s contour.log file on the server. For example, if a report contained the line:
#set($projectDao = $applicationContext.getBean("projectDAO"))
 

2015-12-22 06:48:00,996 INFO  Thread-1110  [.service.VelocityReportService] - <<<<< Running Velocity Report >>>>>
2015-12-22 06:48:01,008 ERROR Thread-1110  [ware.contour.util.ReportRender] - Can't render.
org.apache.velocity.exception.MethodInvocationException: Invocation of method 'getBean' in  class org.springframework.web.context.support.XmlWebApplicationContext threw exception org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'projectDAO' is defined at 31[line 1, column 40]
 
The bean name is case sensitive - it should be "projectDao" instead of "projectDAO."

#tutorial #velocity
2 comments
1038 views

Comments

01-07-2016 18:10

Thanks for sharing. 

01-07-2016 17:58

This is my new favorite post!!!!! THANK YOU!