Chapter 9. Using Java to Write an Event Handler

Creating a Java event handler is more complex than creating a JavaScript event handler. You cannot type Java code directly in BIRT Report Designer.

To create a Java event handler class, compile the source for the Java class and make the class 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.

Writing a Java event handler class

To provide one or more Java event handlers for a scriptable BIRT element, 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. You provide code for only the event handlers that you want to implement.

Locating the JAR files for a BIRT event handler

Each of two JAR files contains 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. Use either JAR file to develop a custom event handler.

The first JAR file that you can 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 second JAR file that you use when you develop and 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 the deployed report classpath, so scriptapi.jar is accessible at run time. To use the scriptapi.jar file in the development phase, download the Report Engine and reference scriptapi.jar from within the build path.

The required JAR files are also in the ReportEnginelib directory of BIRT Report Engine. If you are using the Report Engine API to run reports, add the JAR files in this directory to the classpath and build path. If you are using the report engine plug-in in an Eclipse application, this step is not required, because the plug-in already contains the dependency and classpath entries.

Extending an adapter class

An element adapter class implements the element 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. The steps assume that the Java perspective is open and that a Java project exists in the workspace.

1 Add org.eclipse.birt.report.engine_<version>.jar to a Java project, as described in the following steps:

1 In Navigator, select a Java project and choose File→Properties. In Properties, select Java Build Path→Libraries. In Java Build Path, choose Add External JARs.

2 In JAR Selection, navigate to the Eclipse /plugins directory. In a default Eclipse installation, this directory is in the following location:

<ECLIPSE_INSTALL>eclipseplugins

3 Select org.eclipse.birt.core_<version>.jar. Use control-click to select org.eclipse.birt.report.engine_<version>.jar. Choose Open. Java Build Path appears, as shown in Figure 9-1. Choose OK.

Figure 9-1 The report engine JAR file in the build path

image

2 Select the Java project and choose File→New→Class.

3 To set up the Java class properties, perform the following steps in New Java Class:

1 Navigate to the folder where you want the Java source file to reside by choosing the Browse button beside Source Folder.

2 If the new Java class is a part of a package, type the fully qualified package name in Package.

3 In Name, type a name for the class.

4 In Modifiers, select Public.

5 Select the ROM element event adapter class to extend:

• Choose the Browse button beside Superclass.

• In Superclass Selection, in Choose a type, type the name of the event adapter class for the ROM element. For example, for a label element, type LabelEventAdapter, as shown in Figure 9-2.

Figure 9-2 Selecting a Superclass

image

• Choose OK.

4 In New Java Class, select Generate comments. New Java Class appears similar to the one shown in Figure 9-3.

Figure 9-3 New Java Class final properties

image

5 Choose Finish. The Java editor appears, similar to the one shown in Figure 9-4.

Figure 9-4 The new class in the Java editor

image

6 Add the event handler method for the event handler class. Import all required classes. Figure 9-5 shows the addition of an onPrepare( ) method that sets the background color of a label to red.

Figure 9-5 The onPrepare( ) method in the Java editor

image

7 Choose File→Save.

Making the Java class visible to BIRT

One way to make a Java event handler class visible to the BIRT report designer is to create a Java development project to compile the class in the same workspace as the BIRT report project. The other option is to place the class in a directory or JAR file specified in the BIRT classpath. To deploy the report to an application server, copy the Java class to the appropriate location on the server.

Associating a Java event handler class with a report element

After creating the Java event handler class and coding the appropriate handler methods, associate the class with a report element.

How to associate a Java class with a report element

The steps in this procedure make the following assumptions:

• A report design is open in the Report Design perspective.

• 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.

1 In Outline, select the report element for which an event handler class is visible to BIRT, as shown in Figure 9-6.

Figure 9-6 Selecting a report element

image

2 In Property Editor, choose Event Handler, as shown in Figure 9-7.

Figure 9-7 Event handler properties

image

3 Choose Browse. Class Selection shows available event handler classes.

4 Select the event handler class that extends the BIRT ROM event adapter class, as shown in Figure 9-8. Then, choose OK.

Figure 9-8 Selecting the event handler class

image

The fully qualified name of the event handler class appears in Property Editor, as shown in Figure 9-9.

Figure 9-9 The event handler class name

image

5 Preview the report. The label’s background color is red.

BIRT Java interface and class naming conventions

BIRT event handler class and interface names use the following conventions:

• Event handler interfaces

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.

• Event handler adapter classes

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.

• ROM element instance interfaces

All BIRT ROM element instance interface names begin with the letter I, followed by the name of the element and then Instance. For example, the ROM element instance interface for a Label element is ILabelInstance.

• ROM element design interfaces

All BIRT ROM element instance design interface names begin with the letter I, followed by the name of the element. For example, the design interface for a Label element is ILabel.

Writing a Java event handler

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.

You can give an event handler class any name you choose. Associate the class with a report element in BIRT Report Designer in the Properties view, as explained earlier in this chapter. The Java event handler class can either extend an adapter class or implement an event handler interface. The following sections explain adapter classes and handler interfaces.

Using event handler adapter classes

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, 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 the class compiles 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 compiles even if you do not change the method with the changed signature, but the method with the wrong signature is never called.

Using event handler interfaces

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.

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 to 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. If, however, the event handler class implements an interface instead of extending an adapter class, Java does not 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.

About the Java event handlers for report items

You can write an event handler for any or all of the events that BIRT fires for a report item. Table 9-1 describes the events BIRT fires for each report item.

Table 9-1 Report item event handler methods

image

Using Java event handlers for a data source element

The DataSource event handler interface has four methods that you can use 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 IDataSourceInstance object. These interfaces are discussed later in this chapter. Table 9-2 lists the methods that you can implement for a DataSource element.

Table 9-2 Data source event handler methods

image

Using Java event handlers for a data set element

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. Table 9-3 lists the methods that you can implement for a DataSet element.

Table 9-3 Data set event handler methods

image

Using Java event handlers for a scripted data source element

The scripted data source interface extends the IDataSourceEventHandler interface, which has four methods. The ScriptedDataSource interface adds two new methods to the four methods 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 9-4 lists the two additional methods that you must implement for a ScriptedDataSource element.

Table 9-4 Scripted data source event handler methods

image

Using Java event handlers for a scripted data set element

The scripted data set interface extends the IDataSetEventHandler interface, which has four methods. The scripted data set 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 scripted data set event handlers must implement the IScriptedDataSetEventHandler interface or extend the ScriptedDataSetAdapter class. A Java class that provides scripted data set event handlers must implement the four methods of the IScriptedDataSetEventHandler interface plus the four methods of the IDataSourceEventHandler interface, which it extends. Table 9-5 lists the four additional methods that you must implement for a scripted data set element.

Table 9-5 Scripted data set event handler methods

image

Using Java event handlers for a report design

BIRT fires several events that the report design 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 9-6 lists the methods that you can implement for a ReportDesign element in the order in which they run.

Table 9-6 ReportDesign event handler methods

image

Understanding the BIRT interfaces

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:

• Element design

• IReportElement

• Element instance

• Report context

• IColumnMetaData

• IDataSetInstance

• IDataSourceInstance

• IDataSetRow

• IRowData

About the element design interfaces

Every element has a unique element design interface. The Java interface specifies methods for accessing and setting specific features of the element design. Every element design interface inherits methods from IReportElement.

About the methods for each report element

As well as the methods defined in IDesignElement, each report element has methods that are relevant only for that report element. For example, ICell, the design interface for a Cell object, includes the following methods in addition to those defined in IDesignElement:

• getColumn( )

• getColumnSpan( )

• getDrop( )

• getHeight( )

• getRowSpan( )

• getWidth( )

• setColumn( int column )

• setColumnSpan( int span )

• setDrop( java.lang.String drop )

In contrast, the methods for ITextItem, the design interface for a text element, includes these additional methods:

• getContent( )

• getContentKey( )

• getContentType( )

• getDisplayContent( )

• setContent( java.lang.String value )

• setContentKey( java.lang.String resourceKey )

• setContentType( java.lang.String contentType )

About the IReportElement interface

The IReportElement interface is the base interface for all the report element interfaces. IReportElement has the following methods:

• getComments( )

• 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 )

About the element instance interfaces

The element instance interfaces are available at run time, but not at design time. These interfaces provide access to the run-time instance of the element. Both onCreate( ), the generation phase event handler, and onRender( ), the presentation phase event handler, receive the element instance interface as an argument. 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 vary from element type to element type. For example, ICellInstance, the Cell instance interface, contains the following methods:

• getColSpan( )

• getColumn( )

• getRowSpan( )

• setColSpan( int colSpan )

• setRowSpan( int rowSpan )

By comparison, IRowInstance, the Row instance interface, contains these methods:

• getBookmarkValue( )

• getHeight( )

• getStyle( )

• setBookmark( )

• setHeight( )

Using the IReportContext interface

All event handlers except those for ScriptedDataSource and ScriptedDataSet objects use an object of type IReportContext. The IReportContext interface includes the methods shown in Table 9-7.

Table 9-7 IReportContext interface methods

image

image

image

Using the IColumnMetaData interface

The IColumnMetaData interface provides information about the columns of the data set. Table 9-8 lists the methods in the IColumnMetaData interface.

Table 9-8 IColumnMetaData interface methods

image

Using the IDataSetInstance interface

The IDataSetInstance interface provides access to many aspects of the data set and associated elements. Every DataSet event handler method receives an IDataSetInstance object as an argument. Table 9-9 describes the methods in the interface IDataSetInstance.

Table 9-9 IDataSetInstance interface methods

image

Using the IDataSetRow interface

An object of the IDataSetRow type passes to the DataSet.onfetch( ) event handler method. IDataSetRow has 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. Table 9-10 lists the methods in the IDataSetRow interface.

Table 9-10 IDataSetRow interface methods

image

Using the IRowData interface

The getRowData( ) method of IReportElementInstance, which every report element instance interface extends, returns an object of the IRowData type. IRowData provides access to the bound values that appear in the table or list. 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 that specifies the required column. Table 9-11 lists the methods in the IRowData interface.

Table 9-11 RowData interface methods

image

Java event handler example

The following list provide some common examples that illustrate event handlers written in Java. The examples illustrated in Chapter 8, “Using JavaScript to Write an Event Handler,” can be used as reference as well.

Report level events

Report level events include initialize, beforeFactory, afterFactory, beforeRender, and afterRender. When these events are called depends on the type of report execution occurring.

The beforeFactory( ) method is often overridden, because changes to the report design can occur in this event handler. Listing 9-1 checks a boolean parameter. If this value is true, the report design drops a table named Mytable.

Listing 9-1 Using the Report Engine API in beforeFactory


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.element
   .IReportDesign;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .ReportEventAdapter;
import org.eclipse.birt.report.model.api.*;
import org.eclipse.birt.report.model.api.activity
   .SemanticException;

public class MyReportEvents extends ReportEventAdapter {
   @Override
   public void beforeFactory(IReportDesign report,
      IReportContext reportContext) {
      if((Boolean)reportContext.getParameterValue( "DropTable" )){
         ReportDesignHandle rdh = ( ReportDesignHandle )
            reportContext.getReportRunnable( ).getDesignHandle( );
         try{
            rdh.findElement( "Mytable" ).drop( );
         }catch( SemanticException e ){
            e.printStackTrace( );
         }
      }
   }

This example, using the Design Engine API, requires adding modelapi.jar and coreapi.jar to the buildpath and classpath. This example also uses the Design Engine API to add a data source, data set, and table to a report using the beforeFactory event.

In Listing 9-2, the library mylibrary.rptlibrary, located in the resource folder, opens. The data source named mydatasource, the data set named mydataset, and the table named mytable are all added to the current report design.

Listing 9-2 Using the Design Engine API in beforeFactory


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.element
   .IReportDesign;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .ReportEventAdapter;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.LibraryHandle;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.core.DesignSession;

public class MyReportAddTableEvent extends ReportEventAdapter {
   @Override
   public void beforeFactory( IReportDesign report,
      IReportContext reportContext ) {
      ReportDesignHandle rdh = ( ReportDesignHandle )reportContext
            .getReportRunnable( ).getDesignHandle( );
      DesignSession ds =rdh.getModule( ).getSession( );
      try{
         String rsf = ds.getResourceFolder( );
         LibraryHandle libhan = ds.openLibrary(
            rsf + "/mylibrary.rptlibrary" ).handle( );
         DesignElementHandle deh1 =
            libhan.findDataSource( "mydatasource" );
         DesignElementHandle deh2 =
            libhan.findDataSet( "mydataset" );
         DesignElementHandle deh3 =
            libhan.findElement( "mytable" );
         rdh.getDataSources( ).add( deh1 );
         rdh.getDataSets( ).add( deh2 );
         rdh.getBody( ).add( deh3 );
         libhan.close( );
      }catch(Exception e){
         e.printStackTrace( );
      }
   }
}

Report item events

Report item events support changing the default behavior of an item. Changes made in the onPrepare event can change the design of the item, changes made in the onCreate event can change the particular instance of an item at generation time, and the onRender event can change properties of an instance of the item at render time. Consider the image item example in Listing 9-3.

This example illustrates changing image sources for different types of image items. If the image type is a URL image, the output format is checked and the URL for the image changes. If the image type is a file from the resource folder, the filename is searched for the string, up. If this string is found the image is replaced with an image with the name, down. If the image type is an embedded image, the report parameter, SwapImage, is checked. If the value is true, the image is swapped to another embedded image. If the image is a BLOB type image from a database, the bytes for the image are swapped to the bytes read from the local file system.

Listing 9-3 Changing report item properties in onRender


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .ImageEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance
   .IImageInstance;
import org.eclipse.birt.report.engine.content.IImageContent;
import java.io.*;

public class myImageHandler extends ImageEventAdapter {

   public void onRender( IImageInstance image,
      IReportContext reportContext ) {
      if( image.getImageSource( ) == IImageContent.IMAGE_URL ){
      if( reportContext.getOutputFormat( )
         .equalsIgnoreCase( "html" )){
         image.setURL(
         "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif" );
      } else {
         image.setURL(
         "http://www.google.com/intl/en_ALL/images/logo.gif" );
      }
   }
   if( image.getImageSource( ) == IImageContent.IMAGE_FILE ){
      String rpl = image.getFile( );
      if( rpl.contains( "up" ) ){
         String newstr = rpl.replaceAll( "up", "down" );
         image.setFile( newstr );
      }
   }
   if( image.getImageSource( ) == IImageContent.IMAGE_NAME ){
      if( ( Boolean )reportContext
         .getParameterValue( "SwapImage" ) ){
         if( image.getImageName( ).compareToIgnoreCase(
            "tocico.png" ) == 0 ){
            image.setImageName( "clientprintico.PNG" );
         }
      }
   }
   if( image.getImageSource( ) ==
      IImageContent.IMAGE_EXPRESSION){
      try{
         File myfile = new File( "c:/temp/test.png" );
         FileInputStream ist = new FileInputStream( myfile );
         long lengthi = myfile.length( );
         byte[ ] imageData = new byte[ ( int )lengthi ];
         ist.read( imageData );
         ist.close( );
         image.setData( imageData );
      }catch( Exception e ){
         e.printStackTrace( );
      }
   }
}

As stated earlier, onPrepare event handlers can affect the design of a particular report item. In the example shown in Listing 9-4, an onPrepare event handler adds a hyperlink and a table of contents entry to a data element design. The onCreate event is overridden to modify the hyperlink based on the value of the data item instance.

Listing 9-4 Changing report item properties in onCreate and onPrepare


package my.event.handlers;
import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.element.IAction;
import org.eclipse.birt.report.engine.api.script.element
   .IDataItem;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .DataItemEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance
   .IActionInstance;
import org.eclipse.birt.report.engine.api.script.instance
   .IDataItemInstance;
import org.eclipse.birt.report.model.api.elements
   .DesignChoiceConstants;

public class MyDataElementEvent extends DataItemEventAdapter {
   @Override
   public void onCreate( IDataItemInstance data,
      IReportContext reportContext ) {
      IActionInstance ai =data.getAction( );
      if( ( Integer )data.getValue( ) == 10101 ){
         ai.setHyperlink( "http://www.yahoo.com","_blank" );
      }
   }

   @Override
   public void onPrepare(IDataItem dataItemHandle,
      IReportContext reportContext) {
      IAction act =dataItemHandle.getAction( );
      try{
         act.setTargetWindow( "_blank" );
         act.setURI( "'http://www.google.com'" );
         act.setLinkType(
            DesignChoiceConstants.ACTION_LINK_TYPE_HYPERLINK );
         dataItemHandle.setTocExpression("row["ORDERNUMBER"]");
      }catch( Exception e ){
         e.printStackTrace( );
      }
   }
}

Using an onCreate event handler for a row provides access to the bound columns. For example, the code in Listing 9-5 retrieves the QUANTITYORDERED column for each row of data in a table element. If the value is greater than 40, the background for the row is set to green.

Listing 9-5 Accessing bound data values in onCreate


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .RowEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance
   .IRowInstance;

public class MyRowEvents extends RowEventAdapter {
   @Override
   public void onCreate( IRowInstance rowInstance,
      IReportContext reportContext ) {
      try{
      Integer qty =
         (  Integer )rowInstance.getRowData( ).getColumnValue(
            "QUANTITYORDERED" );
      if( qty > 40 ){
         rowInstance.getStyle( ).setBackgroundColor( "green" );
      }
      }catch( Exception e ){
         e.printStackTrace( );
      }
   }
}

Event handlers can share data by using the setPersistentGlobalVariable( ) method on reportContext. This method writes the variable to the report document if generating a report with two processes. Consider an order listing report that requires the last order number to appear in the page header. The report items described and LISTING NEXT shows how to perform this operation when using two processes to generate and render the report.

The master page header contains first, a dynamic text element with the following expression:

"placeholder"+pageNumber;

The generated report produces placeholder1, placeholder2, and so on for all pages in the report. The master page header also contains a data item. An event handler for the onPageBreak event for the data item contains the code in Listing 9-6.

This code adds an array list item for each page. When the onPageBreak event fires, the data item contains the last value for the page. The array list is saved to the report document using the setPersistentGlobalVariable method.

Listing 9-6 Preparing a persistent global variable in the generation phase


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .DataItemEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance
   .IDataItemInstance;
import java.util.*;

public class MyCustomHeaderDataItem extends DataItemEventAdapter {
   @Override
   public void onPageBreak( IDataItemInstance data,
      IReportContext reportContext) {
      ArrayList ar =
         (ArrayList)reportContext.getPersistentGlobalVariable(
            "MyArrayList" );
      if( ar == null ){
         ar = new ArrayList( );
      }
      ar.add( "Page Ends with: " + data.getValue( ) );
      reportContext.setPersistentGlobalVariable(
         "MyArrayList", ar);
   }
}

An onRender event handler for the dynamic text element in the master page header contains the code in Listing 9-7.

This code first verifies that the dynamic text element is correct by checking for the placeholder text in the value of the dynamic text item. The array list produced by the data item is retrieved from the report document using the getPersistentGlobalVariable method. The specific page string is retrieved from the array list by getting the page number from the current value of the dynamic text item.

Listing 9-7 Using a persistent global variable in the presentation phase


package my.event.handlers;

import org.eclipse.birt.report.engine.api.script.IReportContext;
import org.eclipse.birt.report.engine.api.script.eventadapter
   .DynamicTextEventAdapter;
import org.eclipse.birt.report.engine.api.script.instance
   .IDynamicTextInstance;
import java.util.*;
public class MyCustomHeaderDynamicTextItem extends
   DynamicTextEventAdapter {
   @Override
   public void onRender( IDynamicTextInstance text,
      IReportContext reportContext) {
      String cmp = "nomatch";
      if( text.getText( ).length( ) > 10 ){
         cmp = text.getText( ).substring( 0,10 );
      }
      if( cmp.compareToIgnoreCase("placeholde" ) == 0 ){
         ArrayList ar =
            ( ArrayList )reportContext
               .getPersistentGlobalVariable( "MyArrayList" );
         if( ar == null ){
            return;
         }
      Integer ccount =
         Integer.parseInt( text.getText( ).substring( 11 ) )-1;
      text.setText( ( String )ar.get( ccount ) );
      }
   }
}

This technique works only when generation and presentation occur in two separate processes. The reason is that the onRender event for the dynamic text item in the master page fires after the onCreate and onPageBreak events for all report items when using two processes. When using one process, the onRender event fires immediately after the onCreate event for the dynamic text item in the master page header.

Debugging a Java event handler

One of the main advantages of writing an event handler in Java is the ability to debug the code using Eclipse. To assist this process, BIRT supplies a BIRT Report launch configuration to the debugger. Debug the event handler by opening the event handler class in the Java Perspective, setting appropriate break points, and selecting Run→Open Debug Dialog.

Select BIRT Report from the available configurations and choose Launch Configuration. Select the projects that contain reports using the event handler from the list of available projects and choose Debug to launch a separate instance of Eclipse.

In the new instance, navigate to a report that contains a reference to the event handler and choose Preview. Any breakpoints in the event handler fire.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset