Friday, September 19, 2008

Team Project Sets For BIRT

To start with the obvious, one of the advantages of an OSS project is that you use the source code to study, modify, or improve the software as you see fit.  In a large project, like BIRT, it can be difficult to get the source. Worse, the documentation for fetching the source changes with each build.  No one likes to writes docs, but having to re-write docs is particularly tedious.

In the Eclipse world there are two mechanisms that can be used to help tame these project structures and make it easier to get and build the source code from the version control systems.  The release engineering (releng) systems is a comprehensive system that is used to fetch, build and release the Eclipse projects, including BIRT.  Unfortunately, the releng process has a relatively high barrier to entry for someone that is un-familiar with the Eclipse process (its complicated).

The more user focused mechanism for getting a collection of projects from a version control system is the Team Project Set.  Developers can create a Project Set File (PSF) that describes the repositories, projects, and version tags that make up a collection.  Users can use the Import => Team => Team Project Set functionality in the Java Perspective to fetch the projects specified in the PSF.

I have created a simple program that uses the map files that are core to the RelEng process to build PSF files for the BIRT project.  I am working to get this added to the BIRT version control system, but I am hoping to get some feedback on the files before we commit this to the BIRT project.

Here are the direct links to the PSF files:

To use the team project sets files.  Download the file to your local machine.  Put the file into a Java project and open the Java Perspective.  Right click on the file an select Import.  There will be an option in the context menu to Import Project Set.. I don't recommend using that option since you can't run the import in the background.  
When you click Next, you will be taken to a dialog with the name of the .psf file in it.  You will probably want to select the "Run The Import in the Background" option.  You may get a pop-up dialog asking about the repository, if you do simply select the repositories and off it goes. 
The all_projects.psf will fetch close to 200 projects, so you may want to be careful choosing this option.

I currently have the PSF files set up to pull the current release candidates from BIRT and DTP respectively.

   BIRT_2_3_1_RC2_20080910
   DTP_1_6_1_M1_20080725

If you would like to pull a different version of the source you have a couple of options.  First you can pull the PSF files and then just do a string substitution on the version tags.  The other option is to use a subversion client (subclipse or subversive) to check out the conversion project from version control. The project that builds the PSf files is located on my subversion server at http://longlake.minnovent.com/repos/birt_example.

Next you need to pull the org.eclipse.birt.releng project from the dev.eclipse.org server using the /cvsroot/birt repository.  The project can be found under the Head/source folder, anonymous will work as the user name.  Remember you will want to pull the version of the releng project that matches the version you are trying to get from CVS.  

Now you have to open up the ConvertMapToPsf.java file and change lines 30 and 31 to use the appropriate CVS version tags.  You will need to lookup the tags from CVS.  The other popular tag you will want is the BIRT Ganymede Release 2.3.0:

    BIRT_2_3_0_Release_200806181122
    DTP_1_6_release_200806181028
Once you have the tags set, and you have gotten the org.birt.eclipse.releng project, simply run the ConvertMapToPsf.java file as an application and you will see the PSF files.

If you have any problems with the Team Project Sets let me know.  Hopefully we will have this in the product and a part of the BIRT web site soon, your feedback will be helpful.

EDITED TO ADD: Is anyone using stackoverflow.com?  I have been following this startup question and answer site for a while.  If you have questions or comments maybe you want to post them on the related post at stackoverflow.com.  Here is the Post

Thursday, September 11, 2008

Naming Exported files from the BIRT WebViewer

A common question we get on the BIRT news group is how to change the name of an exported document. For instance, exporting to PDF, the developer may wish to have more control on what filename is used for the export. Currently the name used is just the report name followed by the emitter extension (eg MyReport.pdf).

BIRT 2.3.1 which will be released later this month now supplies a solution to this problem. The example web viewer has a setting that can be added to the web.xml that allows you to specify a Java class that will be responsible for generating the name.



<!-- Filename generator class/factory to use -->
<context-param>
<param-name>BIRT_FILENAME_GENERATOR_CLASS
<param-value>org.eclipse.birt.report.utility.filename.DefaultFilenameGenerator
</context-param>








The class specified must implement the IFilenameGenerator interface, which has one method named getFilename. This method is passed four parameters.

baseName – Contains the base filename for the report, with no extension provided.
fileExtension – The extension for the selected operation (ppt for export to PowerPoint).
outputType – The operation being executed. More on this parameter later.
options – Specific options for the operation.

The instance of the IFilenameGenerator is called in multiple locations within the example viewer. When you export the report:



When you export the report data:



And when you use the /document servlet mapping, for example:

http://localhost:8080/WebViewerExample/document?__report=OrderDetails.rptdesign





This URL will run the report and download the rptdocument.

Suppose you wish to have the date in your filename, when exporting the report. To do this, create a class with the following code:



package my.filename.generator;
import java.util.Date;
import java.util.Map;
import org.eclipse.birt.report.utility.filename.*;
public class MyFilenameGenerator implements IFilenameGenerator{

public static final String DEFAULT_FILENAME = "BIRTReport";

public String getFilename( String baseName, String extension, String outputType, Map options )
{
return makeFileName( baseName, extension );
}
public static String makeFileName( String fileName, String extensionName )
{
String baseName = fileName;
if (baseName == null || baseName.trim().length() <= 0)
{
baseName = DEFAULT_FILENAME;
}

// check whether the file name contains non US-ASCII characters
for (int i = 0; i < baseName.length(); i++) {
char c = baseName.charAt(i);

// char is from 0-127
if (c < 0x00 || c >= 0x80) {
baseName = DEFAULT_FILENAME;
break;
}
}

// append extension name
if (extensionName != null && extensionName.length() > 0) {
baseName += (new Date()).toString() + "." + extensionName;
}
return baseName;
}
}





If you check the source, you will notice this is just the default class with one modification.


baseName += (new Date()).toString() + "." + extensionName;


Which just inserts the date into the output.

You can also check the operation type if you wish to set the name based on the operation. Currently the available options for outputType are:

IFilenameGenerator.OUTPUT_TYPE_EXPORT – When exporting report to one of the supported formats.
IFilenameGenerator.OUTPUT_TYPE_DATA_EXTRACTION – When exporting report data.
IFilenameGenerator.OUTPUT_TYPE_REPORT_DOCUMENT – When using the document servlet mapping.

This example is located here.

Vincent Petry from the dev team has also uploaded a Birt Viewer 2.3 User Reference, which describes the settings and parameters available with the example web viewer. This document is informative and is located here.

If you wish to build your own version of the filename generator, make sure to include viewservlets.jar from the WebViewerExample\WEB_INF\lib directory in your build path.

Wednesday, August 20, 2008

Deploying BIRT to a JBoss Portlet


BIRT uses OSGi plugins to implement most of its functionality. This works great in most cases, but when deploying to servers, configuration can be problematic especially if you are new to OSGi. If you have used BIRT’s Report Engine API before you are probably familiar with setting BIRT_HOME or using the EngineConfig.setBirtHome method. This method essentially just points to the location of the BIRT plugins.

The BIRT EngineConfig class also has a method for setting the PlatformContext (setPlatformContext). This method takes an instance of a class that implements the IPlatformContext interface. This interface is fairly simple in that it has only one method, named getPlatform which returns the path that contains the BIRT plugins. BIRT provides two default implementations of this interface (PlatformServletContext and PlatformFileContext). If the setPlatformContext is never called, BIRT defaults to a PlatformFileContext, which looks for a BIRT home location that is either set using:

System.setProperty(“BIRT_HOME”, locationtobirtplugins);
Or
EngineConfig.setBIRTHome(locationtobirtplugins);

The PlatformServletContext class is used when deploying BIRT to a web application and uses resource based operations for locating the plugins which can be included in the application. For an example of using the PlatformServletContext go
here.

This brings us the intent of this post “Deploying BIRT to a JBoss Portlet”. Within the BIRT wiki is an example of deploying BIRT to a portlet. The example is located
here.

This example works fine, but not with JBoss’s Portal Server. The reason for this is in that example the ServletContext is used to locate the BIRT plugins. Within a JBoss Portlet, I found no ready way of retrieving the ServletContext. It may be possible, but instead of going that route I decided to implement my own version of the IPlatformContext interface, which would use the PortalContext to locate the BIRT plugins.

In the example I built, I just copied the PlatformServletContext class from the BIRT source and modified it to take a PortletContext instead of a ServletContext. Being that it was only two small changes I will not post it here, but it is in the example. I then modified the example BirtEngine.java class from the portlet example above to create an instance of my new PlatformPortletContext class and set it in the engine config with the following code:



IPlatformContext context = new PlatformPortletContext( pc );
config.setPlatformContext( context );

try
{
Platform.startup( config );
}
catch ( BirtException e )
{
}


I also modified the example above to use the PortletContext to set image directories and base image url. The Portlet code looks like this:



package org.eclipse.birt.examples;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import java.io.IOException;
import java.io.PrintWriter;

//+++++++++++++BIRT
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.core.framework.IPlatformContext;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import java.util.logging.Level;
import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.HTMLRenderOption;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.HTMLServerImageHandler;
import java.util.logging.*;
public class JbossBirtPortlet extends javax.portlet.GenericPortlet {
/**
*
*/
private static final long serialVersionUID = 1L;

/**
* Constructor of the object.
*/
private IReportEngine birtReportEngine = null;
protected static Logger logger = Logger.getLogger( "org.eclipse.birt" );
public JbossBirtPortlet() {
super();
}
/**
* Destruction of the portlet.
*/
public void destroy() {
super.destroy();
BirtEngine.destroyBirtEngine();
}
protected void doView(RenderRequest rRequest, RenderResponse rResponse) throws PortletException, IOException, UnavailableException {
rResponse.setContentType("text/html");
this.birtReportEngine = BirtEngine.getBirtEngine(rRequest.getPortletSession().getPortletContext());
logger.log( Level.FINE, "image directory " + rRequest.getPortletSession().getPortletContext().getRealPath("/images"));
IReportRunnable design;
try
{
//Open report design
design = this.birtReportEngine.openReportDesign( rRequest.getPortletSession().getPortletContext().getRealPath("/Reports/TopNPercent.rptdesign"));
//create task to run and render report
IRunAndRenderTask task = birtReportEngine.createRunAndRenderTask( design );
//set output options
HTMLRenderOption options = new HTMLRenderOption();
options.setOutputFormat(HTMLRenderOption.OUTPUT_FORMAT_HTML);
options.setImageHandler( new HTMLServerImageHandler() );
options.setOutputStream(rResponse.getPortletOutputStream());
options.setBaseImageURL(rRequest.getContextPath()+"/images");
options.setImageDirectory(rRequest.getPortletSession().getPortletContext().getRealPath("/images"));
task.setRenderOption(options);
//run report
task.run();
task.close();
}catch (Exception e){
e.printStackTrace();
throw new javax.portlet.PortletException( e );
}
}

/**
* Initialization of the portlet.
*
* @throws PortletException if an error occure
*/
public void init() throws javax.portlet.PortletException {
BirtEngine.initBirtConfig();
}
}






A couple of things to note: Doing it this way requires that the BIRT plugins be included as part of the Portlet WAR. This can create big war files. A better approach may be to deploy the BIRT plugins to a hard location on the system and use the system property and the default PlatformFileContext class to set the BIRT home. I also had to up the PermGen space for the JBoss AS. If you wish to download the example it is located here. Be sure to read the readme for instructions on building the WAR. The example is based off of the JBoss sample HelloWorld portlet and is located
here.

Wednesday, June 25, 2008

BIRT 2.3 Released



BIRT 2.3 has arrived and with this release many new features are available. Most notable are the JavaScript improvements that include an improved JavaScript Editor (validation, line numbers, code folding), a new JavaScript Debugger, and the ability to add JavaScript files to a report design using the GUI. Also new scripting events are available for crosstabs and charts. BIDI support is also provided in all output formats. Many crosstab enhancements were made, including the ability to display measure data using charts within the crosstab. With BIRT 2.3 crosstabs support derived measures as well.


To read more about the new BIRT 2.3 features see the BIRT New and Notable Features.

To view a webinar on the new feature, check out this Eclipse Live recording. The examples used in this webinar are available on
BIRT-Exchange.

Tuesday, June 10, 2008

BIRT - Help Wanted

The majority of the work on the BIRT project is done by the core BIRT committers. At the same time, we recognize that we have a huge community of users and integrators that may want to dedicate some time back to our community.

Unfortunately, it is a little difficult to find a place to start. Yes, there are a lot of open issues in Bugzilla, but it is difficult to determine which items would be best to take on. Unless you are well versed on the internals of BIRT, it is difficult to tell which items are easy, and which are difficult. To complicate things a bit, those items that are easy and relatively high priority tend to get fixed pretty quickly.

In an effort to provide better entry points for people that are interested in contributing code to the BIRT project, we have started to tag bugzilla entries with the keyword "helpwanted". You can find the bugs by using this search. The assumption is that discussion and contributions towards the resolution would be handled through Bugzilla.

If you do come up with a contribution for the BIRT team, please make sure that you select the IP review box if you are submitting code. Also please note that the helpwanted tag is new effort for the BIRT team, and will be a bit of a work in progress.

One other friendly reminder is that the BIRT team is in the closing cycles of the Ganymede release at the end of this month. If you decided to get active, please understand that the entire development team is very focused on the release and may take a while to respond to your contributions and questions.

Friday, May 23, 2008

Designing High Performance BIRT Reports

Over the last couple of months BIRT-Exchange has hosted many webinars explaining and demonstrating BIRT technology. Last weeks webinar featured Mica Block discussing BIRT performance. In this presentation, Mica explains how to gauge performance and provides tips for improving generation time. If you missed it or any of the others, they are available
here.

In addition the following topics will be discussed in the future:

5/30/2008
Using the BIRT Report Engine API
Virgil Dodson

6/13/2008
Using the BIRT Design Engine API
Jason Weathersby

6/27/2008
What's New with BIRT 2.3
Virgil Dodson

7/11/2008
Ad-hoc BIRT Reporting for End Users
Rob Murphy

7/25/2008
BIRT Charting Primer
Virgil Dodson

8/8/2008
Using the BIRT Chart API
Jason Weathersby

Thursday, May 22, 2008

Embed HTML

So this is a really simple problem that Jason solved for me. If you have HTML in your database and you want to embed it into your report as HTML you need to do a few things. First start with a Text control.

1) Change the top drop-down to HTML

2) Change the second drop-down to Dynamic Text

3) Click on the tag and use the expression builder to select the appropriate field.





4) Manually insert the attribute format="HTML" into the VALUE-OF entity













If you follow these steps your HTML text will show up in your report document as formatted text that obeys the HTML rules.