Creating a Java event handler is slightly more complex than creating a JavaScript event handler because you cannot simply enter Java code directly in the BIRT report designer. To create a Java event handler class, you must compile the source for the Java class and make certain that the class is visible to BIRT. Creating a Java event handler for BIRT is simplified, however, by the fact that Eclipse is a robust Java development environment and supports integrating a Java project with a BIRT project.
This chapter discusses the following topics:
Writing the event handler class
Making the event handler class visible to BIRT
Associating the event handler class with a report item
Understanding the classes and interfaces associated with Java event handlers
When you provide one or more Java event handlers for a scriptable BIRT element, you must create one class that contains all the Java event handlers for that element. Creating a class that contains event handler methods for more than one element is not advisable.
BIRT provides a set of Java interfaces and Java adapter classes to simplify the process of writing a Java event handler class. There is one interface and one adapter class for every scriptable BIRT element. An element’s event handler interface defines all the event handler methods for that element. A handler class must implement every method defined in the interface, even if some of the methods are empty.
There are two JAR files that contain all the classes and interfaces that an event handler requires. One of the JAR files is a part of BIRT Report Designer and SDK and the other one is a part of BIRT Report Engine.
The JAR file that you use for developing a Java event handler is org.eclipse.birt.report.engine_Version.jar, which is located in the Eclipse plugins directory for BIRT Report Designer and SDK.
The JAR file that you use when you deploy your report is scriptapi.jar, which is located in the WebViewerExampleWEB-INFlib directory of BIRT Report Engine. All JAR files in the WebViewerExampleWEB-INFlib directory are in a deployed report’s classpath, so there is no need to do anything special to make scriptapi.jar accessible at run time.
An element’s adapter class implements the element’s interface and provides empty stubs for every method. To use the adapter class, extend the adapter class and override the methods for which you are providing handler code. Eclipse recommends extending an adapter class rather than implementing an interface directly.
BIRT naming conventions for the event handler interfaces and adapter classes are discussed later in this chapter.
How to create an event handler class and add it to the Java project
This section describes the process for using the Eclipse Java development environment to create an event handler class for a scriptable BIRT element.
Add org.eclipse.birt.report.engine_Version.jar to your Java project, as outlined in the following steps:
Select your Java project and choose File→Properties→Java Build Path→Libraries. Java Build Path appears, as shown in Figure 10-1.
Navigate to Eclipse /plugins directory. In a default Eclipse installation, this directory is in the following location:
C:eclipseplugins
Select org.eclipse.birt.report.engine_Version.jar. Choose Add. Java Build Path appears.
Choose OK.
Select your Java project and choose File→New→Other. Select a wizard appears.
Expand Java and select Class, as shown in Figure 10-2.
Choose Next. Java Class appears, as shown in Figure 10-3.
Navigate to the folder where you want the Java source file to reside by choosing the Browse button beside Source Folder.
If your new Java class is a part of a package, type the fully qualified package name in Package.
In Name, type a name for your class.
In Modifiers, choose Public.
Choose the Browse button beside Superclass. Superclass Selection appears, as shown in Figure 10-4.
In Choose a type, type the name of the adapter class for the ROM element. For example, enter Label EventAdapter for the Label element. Choose OK. New Java Class reappears.
Select Generate comments. Choose Finish. A Java editor view appears, similar to the one shown in Figure 10-5.
Add the event handler method for your new event handler class. Figure 10-6 shows the addition of an onPrepare( ) method that sets the background color of the label to red.
One way to make a Java event handler class visible to the BIRT report designer is to create a Java development project for compiling the class in the same workspace as your BIRT report project. The other option is to place the class in a directory or JAR file that is specified in the BIRT classpath. When you deploy the report to an application server, however, you must copy the Java class to the appropriate location on the server. For more information about deploying Java classes to an application server, see the chapter about deploying BIRT to an application server.
After you create the Java event handler class and code the appropriate handler methods, you must associate the class with the appropriate report element.
How to associate a Java class with a report element
The example in this procedure makes the following assumptions:
The report design includes a scriptable report item, such as a label.
A Java class containing event handler methods for the scriptable report item is visible to BIRT.
In Outline, select the report element for which an event handler class is visible to BIRT, as shown in Figure 10-7.
In Property Editor for the selected report element, select Event Handler and enter the fully qualified name of your event handler class, as shown in Figure 10-8.
When working with BIRT Java event handlers, you encounter event handler interfaces, adapter classes, element instance interfaces, and element design interfaces. All BIRT event handler classes and interfaces are named using consistent naming conventions.
All BIRT ROM element interface names begin with the letter I, which is followed by the name of the ROM element and then EventHandler. For example, the interface for the Label element is ILabelEventHandler.
All BIRT ROM element adapter class names begin with the name of the element, followed by EventAdapter. For example, the name of the adapter class for a Label element is LabelEventAdapter.
Most scriptable elements have more than one event for which you can write a handler. If you write an event handler for any event of an element, the event handler class must include methods for all the events for that element. You can leave empty those methods that do not require handler code but the empty methods must appear in the class.
You can give an event handler class any name you choose. You associate the class with a report element in BIRT Report Designer in the Properties view, as explained earlier in this chapter. Your Java event handler class can either extend an adapter class or implement an event handler interface. Adapter classes and handler interfaces are explained in the next sections.
BIRT provides event handler adapter classes for every scriptable report element. An event handler adapter class contains empty methods for every event handler method for the element. If your class extends an adapter class, you need to override only the methods for the events for which you want to provide handler code.
One advantage of using an adapter class instead of implementing an interface is that your class will compile even if methods are added to the interface in a future release. If the signature of an event handler method changes in a future release, however, you must change your implementation of that method to reflect the signature change. The class will compile even if you do not change the method with the changed signature, but the method with the wrong signature will never be called.
BIRT provides event handler interfaces for every scriptable report element. If your event handler class extends an adapter class, the adapter class implements the correct interface. If your class does not extend an adapter class, then your class must implement the appropriate interface for the report element you are scripting.
There are some advantages of specifying an interface instead of extending an adapter class. Eclipse generates stubs for every method the interface specifies. The stubs show the method arguments, so you can see the argument types of the methods you must implement. If your class extends an adapter class, there are no generated stubs for you to examine. You also have more freedom in the design of your class structure if you avoid using an adapter class. For example, you might want two or more event handler classes to extend a single base class. Because Java does not support multiple inheritance, the event handler class cannot extend both the adapter class and the base class. However, if the event handler class implements an interface instead of extending an adapter class, there is nothing to prevent the event handler class from extending the base class.
The disadvantage of using an interface over an adapter class is that if additional methods are added to an interface in a future release, a class that implements the interface fails to compile.
You can write an event handler for any or all the events that BIRT fires for a report item. Table 10-1 describes the events BIRT fires for each report item.
Table 10-1. Report item event handler methods
Method | Description |
---|---|
onPrepare( ) | The onPrepare( ) method for every report element contains the following two arguments:
|
onCreate( ) | The arguments to the onCreate( ) method depend on the particular element. Every onCreate( ) method contains at least the following two arguments:
|
onPageBreak( ) | The onPageBreak( ) method for every report element contains the following two arguments:
|
onRender( ) | The onRender( ) method for every report element contains the following two arguments:
|
The DataSource event handler interface has four methods that you can implement to respond to events. A Java class to handle these events must implement the IDataSourceEventHandler interface or extend the DataSourceAdapter class.
All the event methods receive an IReportContext object. All the methods except the afterClose( ) method also receive an IDataSetInstance object. The onFetch( ) method also receives an IDataSetRow object. These interfaces are discussed later in this chapter. Table 10-2 lists the four methods that you can implement for a DataSource element.
Table 10-2. DataSource event handler methods
Method | Description |
---|---|
beforeOpen( IDataSourceInstance dataSource, IReportContext reportContext ) | The beforeOpen event fires immediately before opening the data source. This handler is often used to change the connection properties, such as user name and password. |
afterOpen( IDataSourceInstance dataSource, IReportContext reportContext ) | The afterOpen event fires immediately after opening the data source. |
beforeClose( IDataSourceInstance dataSource, IReportContext reportContext ) | The beforeClose event fires immediately before closing the data source. |
afterClose( IReportContext reportContext ) | The afterClose event fires immediately after closing the data source. |
BIRT fires five events for the DataSet element. A Java class to handle these events must implement the IDataSetEventHandler interface or extend the DataSetAdapter class. All DataSet event handler methods receive an IReportContext object. Additionally, all DataSet event handler methods except the afterClose( ) method receive an IDataSetInstance object. The onFetch( ) method receives a third object, an IDataSetRow object. These interfaces are described later in this chapter. Table 10-3 lists the five methods that you can implement for a DataSet element.
Table 10-3. DataSet event handler methods
Description | |
---|---|
beforeOpen( IDataSetInstance dataSet, IReportContext reportContext ) | The beforeOpen event fires immediately before opening the data set. This event handler is often used to change the query text for a data set. |
afterOpen( IDataSetInstance dataSet, IReportContext reportContext ) | The afterOpen event fires immediately after opening the data set. |
onFetch( IDataSetInstance dataSet, IDataSetRow row, IReportContext reportContext ) | The onFetch event fires upon fetching each row from the data source. |
beforeClose( IDataSetInstance dataSet, IReportContext reportContext ) | The beforeClose event fires immediately before closing the data set. |
afterClose( IReportContext reportContext ) | The afterClose event fires immediately after closing the data set. |
The ScriptedDataSource interface extends the IDataSourceEventHandler interface, which has four methods. The ScriptedDataSource interface adds two new methods to the four of the IDataSourceEventHandler interface. A Java class that provides the ScriptedDataSource event handlers must implement IScriptedDataSourceEventHandler interface or extend the ScriptedDataSourceAdapter class. A Java class that provides the ScriptedDataSource event handlers must implement the two methods of the IScriptedDataSourceEventHandler interface plus the four methods of the IDataSourceEventHandler interface, which it extends.
Both of the two event handler methods of IScriptedDataSourceEventHandler receive an IDataSourceInstance object. Table 10-4 lists the two additional methods that you must implement for a ScriptedDataSource element.
The ScriptedDataSet interface extends the IDataSetEventHandler interface, which has four methods. The ScriptedDataSet interface adds four new methods to the four of the IDataSourceEventHandler interface. Of the four new methods, three must be fully implemented and the fourth may be empty. A Java class that provides the ScriptedDataSet event handlers must implement IScriptedDataSetEventHandler interface or extend the ScriptedDataSetAdapter class. A Java class that provides the ScriptedDataSet event handlers must implement the four methods of the IScriptedDataSetEventHandler interface plus the four methods of the IDataSourceEventHandler interface, which it extends.
Table 10-5 lists the four additional methods that you must implement for a ScriptedDataSet element.
Table 10-5. ScriptedDataSet event handler methods
Method | Description |
---|---|
open( IDataSetInstance dataSet ) | Called when the data set is opened. Use this method to initialize variables and to prepare for fetching rows. |
fetch( IDataSetInstance dataSet, IUpdatableDataSetRow dataSetRow ) | Called at row processing time. Use this method to fetch data with which to populate the row object. This method must return true if the fetch is successful and false if it is not. |
close( IDataSetInstance dataSet ) | Called upon completion of processing a data set. Use this method to perform cleanup operations. |
describe( IDataSetInstance dataSet, IScriptedDataSetMetaData metaData metaData ) | Use this method to define the column names and types of the data set. |
BIRT fires several events that the ReportDesign element handles. A Java class to handle these events must implement the IReportEventHandler interface or extend the ReportEventAdapter class. All of the event handler methods receive an IReportContext object. The beforeFactory( ) method also receives an IReportDesign object. Table 10-6 lists the methods that you can implement for a ReportDesign element in the order in which they fire.
Table 10-6. ReportDesign event handler methods
Method | Description |
---|---|
initialize( IReportContext reportContext ) | The initialize event is fired twice, once before the generation phase begins and once before the render phase begins. |
beforeFactory( IReportDesign report, IReportContext reportContext ) | The beforeFactory event is fired before the generation phase begins. |
afterFactory( IReportContext reportContext ) | The afterFactory event is fired after the generation phase ends. |
beforeRender( IReportContext reportContext ) | The beforeRender event is fired before the presentation phase begins. |
afterRender( IReportContext reportContext ) | The afterRender event is fired after the presentation phase ends. |
A developer of Java event handlers needs to be familiar with several Java interfaces. Most of the handler method parameters and return values are Java interfaces rather than classes.
The most important Java interfaces for developing Java event handlers are:
The element design interfaces
The IReportElement interface
The element instance interfaces
The report context interfaces
The IColumnMetaData interface
The IDataSetInstance interface
The IDataSourceInstance interface
The IDataSetRow interface
The IRowData interface
Every element has a unique element design interface. The element design is a Java interface that specifies methods for accessing and setting specific features of the element’s design. Every element design interface inherits methods from IReportElement.
Besides the methods defined in IReportElement, each report element has methods that are only relevant for that report element. For example, ICell, the design interface for a Cell object, includes the following methods in addition to those defined in IReportElement:
getColumn( )
getColumnSpan( )
getDrop( )
getHeight( )
getRowSpan( )
getWidth( )
setColumn( int column )
setColumnSpan( int span )
setDrop( java.lang.String drop )
setRowSpan( int span )
In contrast, the methods for ITextItem, the design interface for a TextItem element, includes these additional methods:
getContent( )
getContentKey( )
getContentType( )
getDisplayContent( )
setContent( java.lang.String value )
setContentKey( java.lang.String resourceKey )
setContentType( java.lang.String contentType )
For a complete list of all the design interfaces, see the BIRT Javadoc. To access the Javadoc, choose BIRT Developer Guide→Reference in the online help.
The IReportElement interface is the base interface for all the report element interfaces. IReportElement has the following methods:
getCustomXml( )
getDisplayName( )
getDisplayNameKey( )
getName( )
getNamedExpression( java.lang.String name )
getParent( )
getQualifiedName( )
getStyle( )
getUserProperty( java.lang.String name )
setComments( java.lang.String theComments )
setCustomXml( java.lang.String customXml )
setDisplayName( java.lang.String displayName )
setDisplayNameKey( java.lang.String displayNameKey )
setName( java.lang.String name )
setNamedExpression( java.lang.String name, java.lang.String exp )
setUserProperty( java.lang.String name, java.lang.Object value )
For more information about the methods defined in the IReportElement interface, including the arguments and return values of all its methods, see the BIRT Javadoc in the BIRT online help.
The element instance interfaces are available at run time, but not at design time. They contain the run-time instance of the element. The element instance interface is passed to both onCreate( ), the generation phase event handler, and to onRender( ), the presentation phase event handler.
Through instance interfaces, you have access to a different set of properties than you do at design time. There is no superinterface from which all element instance interfaces inherit. Like the element design interface, the set of methods in the instance interfaces varies from element to element.
For example, ICellInstance, the Cell instance interface, contains the following methods:
By comparison, IRowInstance, the Row instance interface, contains these methods:
getBookmarkValue( )
getHeight( )
getStyle( )
setBookmark( )
setHeight( )
For a complete list of all instance interfaces, see the BIRT Javadoc in the BIRT online help.
An object of type IReportContext is passed to all event handlers except those for ScriptedDataSource and ScriptedDataSet objects. The IReportContext interface includes the methods shown in Table 10-7.
Table 10-7. IReportContext interface methods
Method | Task |
---|---|
deleteGlobalVariable( java.lang.String name ) | Removes a global variable created using the setGlobalVariable( ) method. |
deletePersistentGlobalVariable( java.lang.String name ) | Removes a persistent global variable created using the setPersistentGlobalVariable( ) method. |
getAppContext( ) | Retrieves the application context object as a java.util.Map object. The report application can use the application context object to pass any information that is application-specific.One example of information passed through an application context object is the HTTPSession object. |
getGlobalVariable( java.lang.String name ) | Returns the object saved with the setGlobalVariable( ) method. The string argument is the key with which the object was saved. |
getHttpServletRequest( ) | Returns the HttpServletRequest object associated with the URL requesting the report. The HttpServletRequest object provides access to the request URL and any parameters that are appended to the request. |
Returns the locale associated with the report execution or rendering task. This locale might be different from the local machine’s system or user locale. | |
getMessage( java.lang.String key ) | Returns a message from the default properties file. |
getMessage( java.lang.String key, java.util.Locale locale, java.lang.Object[] params ) | Returns a message from the properties file for a specified locale, using a parameters array. |
getMessage( java.lang.String key, java.lang.Object[] params ) | Returns a message from the default properties file, using a parameters array. |
getOutputFormat( ) | Returns a string containing either html or pdf, depending on which format was specified in the __format parameter of the request URL. |
getParameterValue( java.lang.String name ) | Returns the value of the parameter named in the name argument. The value returned is a java.lang.Object. |
getPersistentGlobalVariable( java.lang.String name ) | Returns the serializable object saved with the setPersistentGlobalVariable( ) method. The string argument is the key with which the serializable object was saved. |
setGlobalVariable( java.lang.String name, java.lang.Object obj ) | Saves an object that can be retrieved in the same execution phase as it is saved. The setGlobalVariable( ) method takes a string argument and an Object argument. You use the string argument as a key with which to later retrieve the saved object. |
setParameterValue( java.lang.String name, java.lang.Object value ) | Sets the value of a named parameter with the value contained in the value parameter. |
setPersistentGlobalVariable( java.lang.String name, java.io.Serializable obj ) | Saves an object that can be retrieved in a different execution phase than it is saved. The setPersistentGlobalVariable( ) method takes a string argument and a serializable object argument. You use the string argument as a key with which to later retrieve the serializable object. The object is serializable because it must be persisted between phases to support executing the two phases at different times and possibly on different machines. The serializable object is saved in the report document. |
The IColumnMetaData interface provides information about the columns of the data set. Table 10-8 lists the methods in the IColumnMetaData interface class.
Table 10-8. IColumnMetaData interface methods
Method | Returns |
---|---|
getColumnAlias( int index ) | The alias assigned to the column at the position indicated by the index argument |
getColumnCount( ) | The count of columns in the data set |
getColumnLabel( int index ) | The label assigned to the column at the position indicated by the index argument |
getColumnName( int index ) | A string containing the name of the column at the position indicated by the index argument |
getColumnNativeTypeName( int index ) | The name of the type of data in the column at the position indicated by the index argument |
getColumnType( int index ) | The data type of the column at the position indicated by the index argument |
getColumnTypeName( int index ) | The name of the type of data in the column at the position indicated by the index argument |
isComputedColumn( int index ) | True or false, depending on whether the column at the position indicated by the index argument is a computed field |
The IDataSetInstance interface provides access to many aspects of the data set and associated elements. An IDataSetInstance object is passed to every DataSet event handler method.
Table 10-9 describes the methods in the interface IDataSetInstance.
Table 10-9. IDataSetInstance interface methods
Method | Returns |
---|---|
getAllExtensionProperties( ) | The data set extension properties in the form of a java.util.Map object. The map object maps data extension names to their values. |
getColumnMetaData( ) | An IColumnMetaData object that provides the data set’s metadata. |
getDataSource( ) | A DataSource object with which the data set is associated. |
The unique ID that identifies the type of the data set, assigned by the extension that implements this data set. | |
getExtensionProperty( java.lang.String name ) | The value of a data set extension property. |
getName( ) | The name of this data set. |
getQueryText( ) | The query text of the data set. |
setExtensionProperty( java.lang.String name, java.lang.String value ) | The value of an extension property. |
setQueryText( java.lang.String queryText ) | The query text of the data set. |
An object of the IDataSetRow type is passed to the DataSet.onfetch( ) event handler method. Table 10-10 lists the methods in the IDataSetRow interface. Note that there are two getColumnValue( ) methods. The two methods differ only in the argument that specifies the column containing the value. They both return a java.lang.Object object, which you must cast to the appropriate type for the column.
An object of the IRowData type is returned from the getRowData( ) method of IReportElementInstance, which every report element instance interface extends.
IRowData provides access to the bound values that appear in the table. The IRowData interface has two getExpressionValue( ) methods. Both methods return the display value for a specific column in the table. The two methods differ in the argument you pass to specify the column that you require. Table 10-11 lists the methods in the IRowData interface.
Table 10-11. IRowData interface methods
Method | Returns |
---|---|
getColumnCount( ) | Return the count of the bounding expressions. |
getColumnName( int index) | Return the name of the bounding expression by id. |
getColumnValue(int index) | Return the value of the bounding expression by id. This index is 1-based. |
getColumnValue(String name) | Return the value of the bounding expression by name. |