icon-developing.png
XNAT Development
Codebase


Best Practices for Development


Mercurial


Other topics

[Edit Nav]

XNAT Codebase: Understanding 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.cnl.xdat.turbine.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 the 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.cnl.xdat.turbine.modules.screens.SecureReport) which handles most of this processing for you. It is expected that your customer report class (XDATScreen_report_{sql_name}.java) will extend this class. It provides one abstract method which ‘public void finalProcessing(RunData data, Context context)’ which must be implemented. This method can be left empty, or any additional processing the developer desires can be added.

The Secure Report Class loads to objects in to 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.cnl.xft.XFTItem. The user object is the current user (org.cnl.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).

Accessing Item properties

Individual properties of the Item are accessible through the getProperty() method of the org.cnl.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() and getBooleanProperty() 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.cnl.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: I 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.cnl.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 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.