Combine Multiple BIRT Designs To Generate Single Report


We use BIRT for generating reports in our application. Currently we have a suite of report designs that covers various parts of the application. Reports are generated on demand by the user. The application required the functionality of specifying a list of birt rpt design files, which can then be run to generate a single report for the user.

It is quite common to have the need to run several reports and then render them all into one report. In practice, this could be achieved by the ability to merge multiple rpt design files to one, or have IReportEngine.createRenderTask method to take an array of IReportDocuments instead of just one. BIRT does not have support for this functionality yet. Have a look at the issue here.

We went ahead to implement this functionality by following approach of running multiple reports and then to combine their output to a single report. We found that it is not very difficult to do so.

Let’s have a look at MergeReportsPDF code listing. It has a main method which after retrieving a list of file paths of rpt design files makes a call to merge them in a single pdf report. If you look closely at the runReport method you will notice that it first initializes the BIRT engine and then loops into the list of file paths to run BIRT task. The runReport method also accumulates this into a list of ByterArrayOutputStream which is then used later to render a combined pdf report using itext. The method renderCombinedReportFromOutputStreams constructs PdfCopyFields with destination FileOutputStream parameter; it then reads in the BIRT report output one by one to construct a list of PdfReader object. Finally it loops in the list of pdfReader to construct a pdf report.

public class MergeReportsPDF {
public static void main(String[] args) {
  List<String> reportFilePathsToMerge = getReportFilePathsToMerge();
  try {
     MergeReportsPDF mergeReports = new MergeReportsPDF();
     mergeReports.runReport(reportFilePathsToMerge);
     } catch (Exception e) {
       e.printStackTrace();
  }
}

private void runReport(List<String> reportFilePathsToMerge) throws Exception {
  List<ByteArrayOutputStream> byteArrayOutputStreams = new ArrayList<ByteArrayOutputStream>();
  IReportEngine engine = initBirtEngine();
  for (String filePath : reportFilePathsToMerge) {
  byteArrayOutputStreams.add(runTaskAndGetOutputStream(filePath, engine));
  }
  renderCombinedReportFromOutputStreams(byteArrayOutputStreams);
  engine.destroy();
  Platform.shutdown();
}
	
private void renderCombinedReportFromOutputStreams(List<ByteArrayOutputStream> byteArrayOutputStreams) throws DocumentException, IOException {
  List<PdfReader> pdfReaders = new ArrayList<PdfReader>();
  PdfCopyFields pdfCopyFields = new PdfCopyFields(new FileOutputStream(DESTINATION_FILE_PATH));

  for (ByteArrayOutputStream byteArrayOutputStream : byteArrayOutputStreams) {
  PdfReader pdfReader = new PdfReader(byteArrayOutputStream.toByteArray());
  pdfReaders.add(pdfReader);
  }
 
 for (PdfReader pdfReader : pdfReaders) {
 pdfCopyFields.addDocument(pdfReader);
 }
 pdfCopyFields.close();
}

private IReportEngine initBirtEngine() throws BirtException {
  EngineConfig config = new EngineConfig();
  config.setBIRTHome(BIRT_HOME);
  config.setLogConfig(null, Level.OFF);
		
  Platform.startup(config);
  IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
  IReportEngine engine = factory.createReportEngine(config);
  return engine;
}
	
private ByteArrayOutputStream runTaskAndGetOutputStream(String filePath, IReportEngine engine) throws EngineException {
  IReportRunnable design = engine.openReportDesign(filePath);
  IRunAndRenderTask task = engine.createRunAndRenderTask(design);
		
  PDFRenderOption options = new PDFRenderOption();
  ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  options.setOutputStream(byteArrayOutputStream);
  options.setOutputFormat("pdf");
		
  task.setRenderOption(options);
  task.run();
  task.close();
		
  return byteArrayOutputStream;
}
	
private static List<String> getReportFilePathsToMerge() {
  List<String> filePaths = new ArrayList<String>();
  filePaths.add(FILE_1);
  filePaths.add(FILE_2);
  return filePaths;
}
}

The approach we followed works but with the caveat that page numbers will not come up and Table Of Contents will not be right either. The ideal scenario would have been if BIRT have a support for merging multiple rpt documents into one with appropriate pagination and table of contents.

This entry was posted in Java and tagged , . Bookmark the permalink.

One Response to Combine Multiple BIRT Designs To Generate Single Report

  1. Prathamesh says:

    Thank you! Snippet worked for us.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s