Understanding the CSV report rendering extension package
The implementation package for the CSV report rendering extension example, org.eclipse.birt.report.engine.emitter.csv, contains the following classes:

CSVPlugin
Defines the methods for starting, managing, and stopping a plug-in instance.

CSVRenderOption
Integrates the plug-in with BIRT Report Engine, specifying configuration information. CSVRenderOption extends RenderOption, specifying the output format as CSV.

CSVReportEmitter
Extends org.eclipse.birt.report.engine.emitter.ContentEmitterAdapter. CSVReportEmitter handles the start and end processing that renders the report container.

CSVTags.java
Defines the comma and new line String settings used when writing to the CSV file.

CSVWriter
CSVWriter writes the data and label contents of the report to the CSV file, using a call to java.io.PrintWriter.print( ). CSVWriter also uses org.eclipse.birt.report.engine.emitter.XMLWriter with java.util.logging.Logger to write log messages at specified levels.
The following sections contain specific information about implementation details for the classes in the CSV report rendering extension package.
Understanding CSVReportEmitter
CSVReportEmitter is the class that extends ContentEmitterAdapter to output the text content of the report items to a CSV file. CSVReportEmitter instantiates the writer and emitter objects.
CSVReportEmitter implements the following methods:

CSVReportEmitter( ) instantiates the CSV report emitter class as an org.eclipse.birt.report.engine.presentation.ContentEmitterVisitor object, to perform emitter operations, as shown in
Listing 19‑1.
Listing 19‑1 The CSVReportEmitter( ) constructor
public CSVReportEmitter( )
{
contentVisitor = new ContentEmitterVisitor( this );
}

initialize( ) performs the following operations required to create an output stream that writes the text contents of the report to the CSV file:

Obtains a reference to the IEmitterServices interface. Instantiates the file and output stream objects, using the specified settings.

Instantiates the CSV writer object.
Listing 19‑2 The initialize( ) method
public void initialize( IEmitterServices services )
{
this.services = services;
Object fd = services.getOption
( RenderOptionBase.OUTPUT_FILE_NAME );
File file = null;
try
{
if ( fd != null )
{
file = new File( fd.toString( ) );
File parent = file.getParentFile( );
if ( parent != null && !parent.exists( ) )
{
parent.mkdirs( );
}
out = new BufferedOutputStream( new
FileOutputStream( file ) );
}
}
catch ( FileNotFoundException e )
{
logger.log( Level.WARNING, e.getMessage( ), e );
}
if ( out == null )
{
Object value = services.getOption
( RenderOptionBase.OUTPUT_STREAM );
if ( value != null && value instanceof OutputStream )
{
out = (OutputStream) value;
} else
{
try
{
file = new File( REPORT_FILE );
out =
new BufferedOutputStream
( new FileOutputStream( file ) );
}
catch ( FileNotFoundException e )
{
logger.log( Level.SEVERE, e.getMessage( ), e );
}
}
}
writer = new CSVWriter( );
}

start( ) performs the following operations:

Obtains a reference to the IReportContent interface.

Sets the start emitter logging level and writes to the log file.

Opens the output file and specifies the encoding scheme as UTF-8.

Starts the CSV writer.
Listing 19‑3 The start( ) method
public void start( IReportContent report )
{
logger.log( Level.FINE,
"[CSVReportEmitter] Start emitter." );
this.report = report;
writer.open( out, "UTF-8" );
writer.startWriter( );
}

end( ) performs the following operations:

Sets the end report logging level and writes to the log file.

Ends the write process and closes the CSV writer.

Closes the output file.
Listing 19‑4 The end( ) method
public void end( IReportContent report )
{
logger.log( Level.FINE,
"[CSVReportEmitter] End report." );
writer.endWriter( );
writer.close( );
if( out != null )
{
try
{
out.close( );
}
catch ( IOException e )
{
logger.log( Level.WARNING, e.getMessage( ), e );
}
}
}
Understanding the other CSVReportEmitter methods
The CSVReportEmitter class defines the following additional methods, called at different phases of the report generation process, that provide access to emitters, render options, and style information to facilitate BIRT Report Engine processing:

startTable( )
When writing to the CSV file, the CSV rendering extension must consider the cell position in the row because a comma appears as the last character in all the cells except the last cell in the row.
The startTable( ) method uses ITableContent.getColumnCount( ) to get information about table column numbers and to initialize the protected columnNumbers variable, as shown in
Listing 19‑5.
Listing 19‑5 The startTable( ) method
public void startTable( ITableContent table )
{
assert table != null;
tableDepth++;
columnNumbers = table.getColumnCount( );
...
}

startRow( )
At the start of each row, startRow( ) performs the following operations:

Calls isRowInFooterBand( ) to determine if the row is in the header or footer band of a table or group.

Sets exportElement to false if the current table element belongs to a table header, footer, or is an image, since this extension exports only label and data elements to the CSV file.

Sets the currentColumn indicator to 0.
Listing 19‑6 The startRow( ) method
public void startRow( IRowContent row )
{
assert row != null;
if ( tableDepth > 1) {
logger.log( Level.FINE,
"[CSVTableEmitter] Nested tables are not supported." );
return;
}
if ( isRowInFooterBand( row ) )
exportElement = false;
currentColumn = 0;
}

isRowInFooterBand( )
If the row is an instance of band content, isRowInFooterBand( ) checks the band type. If the band type is a footer, the method returns true, as shown in
Listing 19‑7.
Listing 19‑7 The isRowInFooterBand( ) method
boolean isRowInFooterBand( IRowContent row )
{
IElement parent = row.getParent( );
if ( !( parent instanceof IBandContent ) )
{
return false;
}
IBandContent band = ( IBandContent )parent;
if ( band.getBandType( ) == IBandContent.BAND_FOOTER )
{
return true;
}
return false;
}

startText( )
If the element is exportable, startText( ) writes the text value to the CSV output file, as shown in
Listing 19‑8.
Listing 19‑8 The startText( ) method
public void startText( ITextContent text )
{
if ( tableDepth > 1) {
logger.log( Level.FINE,
"[CSVTableEmitter] Nested tables are not supported."
);
return;
}
String textValue = text.getText( );
if (exportElement)
{
writer.text( textValue );
}
}

endCell( )
If the current cell is not the last column in the row and the element is exportable, endCell( ) writes a comma to the CSV output file, as shown in
Listing 19‑9.
Listing 19‑9 The endCell( ) method
public void endCell( ICellContent cell )
{
if ( ( currentColumn < columnNumbers )
&& exportElement )
{
writer.closeTag( CSVTags.TAG_COMMA );
}
}

endRow( )
At the end of each row, if the element is exportable, endRow( ) writes a new line or carriage return to the CSV output file, as shown in
Listing 19‑10.
Listing 19‑10 The endRow( ) method
public void endRow( IRowContent row )
if ( exportTableElement )
writer.closeTag( CSVTags.TAG_CR );
exportElement = true;
}
Understanding CSVTags
The CSVTags class defines the contents of the comma and new line tags, as shown in
Listing 19‑11.
Listing 19‑11 The CSVTags class
public class CSVTags
{
public static final String TAG_COMMA = "," ;
public static final String TAG_CR = "\n" ;
}
Understanding CSVWriter
The CSVWriter class writes the closing tags defined in CSVTags, as shown in
Listing 19‑12.
Listing 19‑12 The closeTag( ) method
public void closeTag( String tagName )
{
printWriter.print( tagName );
}
Understanding CSVRenderOption
The org.eclipse.birt.report.engine.emitter.csv.CSVRenderOption class extends org.eclipse.birt.report.engine.api.RenderOption to add the CSV rendering option to the BIRT Report Engine run time, as shown in
Listing 19‑13.
Listing 19‑13 The CSVRenderOption class
public class CSVRenderOption extends RenderOption {
public static final String CSV = "CSV";
public CSVRenderOption( ) {
}
}