XNAT Reports

The XDAT website makes use of Jakarta Turbine’s structure to allow for the easy creation of secured report Screens. Each report has two primary components; a java class and a Velocity page (.vm). For any report you create, you will need to create both of these components.

What happens before XDAT gets to your report?

The XDAT engine takes care of all of the navigation processing for any Report. This processing starts in the org.nrg.xdat.turbine.modules.actions.DisplayItemAction Class. This class is in charge of locating/loading the item that will be displayed and routing the item to the correct Velocity screen. Generally, items are passed to this DisplayItemAction with just a few simple Turbine RunData parameters (Key/Value parameters). The three parameters passed are the schema element name (search_element), the field whose value is sent (search_field) and the matching value (search_value). Example:

KEY

VALUE

search_element

xnat:mrSessionData

search_field

xnat:mrSessionData.ID

search_value

FORGE1_0014_1_MR

These three parameters will then be used to load the appropriate item from the database. The search_field should correspond to either the primary key field or a field with a unique value, to guarantee that only one item is returned. The search_value must correspond to the item’s search_field.

After the DisplayItemAction has loaded the Item, it checks to see if the element has a customized Report. If no customized Report is found, then the item is routed to the default display Screen. ATTENTION: In order for your customized report to be found by the XDAT engine, it must have the proper name and be in the proper location. The name of the File is expected to begin with ‘XDATScreen_report_’ and then contain the SQL version of the element name (the use of the SQL version of the name, guarantees that there will be no special characters in the name (i.e. ‘:’) which could not be used in a file name). The SQL version of the name can be found by finding the corresponding table in the database, and using that table’s name. The files (java and vm) must be in a location which the Turbine Web Application looks (i.e. the templates/screens directory for the vm, and the java class location specified in the TurbineResources.properties).

1. Create the Java Class.
Each report has a java file which is processed before the Velocity screen is constructed. This java file handles loading the necessary objects into the Velocity Context for easy use in the Velocity screen. XDAT provides a Java Class (org.nrg.xdat.turbine.modules.screens.SecureReport) which handles most of this processing for you. It is expected that your custom report class (XDATScreen_report_{sql_name}.java) will extend this class. It provides one abstract method which must be implemented:

public void finalProcessing(RunData data, Context context)

This method can be left empty, or any additional processing the developer desires can be added.

The Secure Report Class loads objects into the Velocity Context for use in the Velocity Screen, item and user. The item object is the actual item to be displayed and is of a type org.nrg.xft.XFTItem. The user object is the current user (org.nrg.xdat.security.XDATUser) which may be used for security purposes.

2. Create the Velocity Screen
The velocity screen is the location of most of the report specifications. The developer can customize this format in any way deemed necessary (See http://velocity.apache.org/engine/devel/user-guide.html for more details). The Item and User objects are referenced through the usual Velocity syntax (i.e. $item or $user).

The web application will look in multiple locations for your report files. This allows you to override the default reports which XNAT generates, and the additional reports which are provided with XNAT. The web application will look in four locations for your Velocity macros (in the following order).
1. WEBAPP_ROOT/projects/xnat/src/templates/screens
2. WEBAPP_ROOT/plugin-resources/webapp/xnat-templates/screens
3. WEBAPP_ROOT/plugin-resources/webapp/xdat-templates/screens
4. WEBAPP_ROOT/projects/xnat/src/base-templates/screens

The initial location (1) is where you should place any reports which you create. If the web application doesn’t find a report in that location, it will look in location (2). This is where pre-customized reports specifically for XNAT are located. Next, it will look in location (3) which is where pre-customized reports for XDAT (security) are located. Finally, it will look in the WEBAPP_ROOT/base-templates/screens (4). This is where XNAT’s setup or update scripts put the generated report screens.


The easiest and quickest way to create a new report, is to copy the generated .vm file from the WEBAPP_ROOT/projects/xnat/src/base-templates/screens
location into the WEBAPP_ROOT/projects/xnat/src/templates/screens location and manipulate the content.

Accessing Item properties

Individual properties of the Item are accessible through the getProperty() method of the org.nrg.xft.XFTItem. The field name can be specified using the dot-syntax name of the field. For example:

$item.getProperty("xnat:MrSession.mrSessionData.ID"))

The getString(), getBooleanProperty(), and getIntegerProperty() methods can be used similarly to receive the values with particular formatting.

There are two ways to access the properties of the children of the Item. First, the developer can obtain a reference to the sub Item directly using the getProperty() method for single reference or the getChildItems() method for multiple referenced children. Both of these methods take in the dot-syntax name of the field. For example:

$item.getChildItems("xnat:mrSessionData.scan"))

The other method to access the properties of the children of the Item involves referencing the child fields directly through dot-syntax. This becomes tricky when you are referencing a child which could have multiple objects. So, numbers can be inserted into the dot_syntax after a reference field name to specify which child you are referencing. For example:

$item.getProperty("xnat:mrSessionData.scan2.number")

The number must be preceded by two ‘_’ characters and starts with 0. This code would return the number field of the third scan (0,1,2) for this session. If there was no third scan, then null would be returned.
Thus, when a developer wants to iterate through multiple children, there are two options.

  • Obtain direct references to the objects:

    #foreach ($scan in $item.getChildItems("xnat:mrSessionData.scan"))
    <TR>
    <TD>$!scan.getProperty("xnat:mrScanType.number")</TD>
    <TD>$!scan.getProperty("xnat:mrScanType.type")</TD>
    <TD>$!scan.getString("xnat:mrScanType.note")</TD>
    </TR>
    #end
    
  • Directly reference the fields using a number in the dot-syntax

     __#foreach($c in [0..10] )
    <TR>
    <TD>$item.getProperty("xnat:mrSessionData.scan $\{c\}.number")</TD>
    <TD>$item.getProperty("xnat:mrSessionData.scan $\{c\}.type")</TD>
    <TD>$item.getProperty("xnat:mrSessionData.scan $\{c\}.note")</TD>
    </TR>
    #end__
    

The primary difference between the two methods is that, the first option will result in only as many rows as there are objects. The second option will have as many rows as is specified in the loop. The second option is useful in edit screens.

Creating Custom Item Classes

The XFTItem structure allows for easy access to items without type casting the item to a specific java type. This provides an excellent generic method for working with data. However, in some instances, the developer may want to create a custom object to wrap that Item, which will allow for greater flexibility and customization. The XDAT engine can create this Item wrapper for you.

There is a specific Command Prompt option for generating extended Java Files for your schema Elements.

Example:

GenerateJavaFile -l LOCATION -p PACKAGE_NAME - e SCHEMA_ELEMENT

The function takes in three parameters :

-l : the location to output the created files.
-p : the package name to use in the java files.
-e : the schema element for the class (or ‘ALL’ to generate all classes).

The function creates two java files for each element; a base class which extends org.nrg.xdat.base and contains the methods for constructing an object and accessing its values, and a extension class which simple extends the base class ( this is where your custom methods should go). If at some point the classes are regenerated, the Base class will be overwritten with the new Class, but the extension class will NOT be overwritten.

If you would like to use this class in a custom report, then you will need to construct the class and load it into the Velocity Context inside of the screen’s corresponding java file (the finalProcessing method). The class will have a constructor that takes the XFTItem. So the statement should be as simple as: JavaClassName n = new JavaClassName(item); To load the item into the context use: context.put(“NAME”, n);

The custom class will now be accessible within the Velocity Screen. Notice, that the custom item has inherited methods to access the defined Display Fields for this element (getDisplayField()). So, if you have defined a corresponding Display document for the item’s schema element, those values can be accessed by passing Display Field IDs into the getDisplayField() method. ATTENTION: In order to access these values, the user must specifically preload the Display Field values (using the loadDisplayFields() method). This is not done automatically, as sometimes it can cause a slow SQL select.

There are numerous methods inherited from org.nrg.xdat.base.BaseElement which allow for easy use of Items and effective access of their properties.

Pre-defined Turbine Velocity Macros

For your convenience, some velocity macros have been predefined in WEBAPP_ROOT/plugin-resources/webapp/xdat-templates/macros/TurbineMacros. For use in reports one macro (elementActionsBox) will be particularly helpful. This macro will list the possible actions for a given item based on the element’s security settings (xnat:element_security). The code to insert this macro into a velocity screen is:

#elementActionsBox($element $search_field $search_value $data.getSession().getAttribute("user") $item)

All of these attributes are passed in from the SecureReport screen, so this code can be inserted without additional work.

$label.name