Monday, May 19, 2008

BIRT deployment

BIRT is an Eclipse reporting project. It comes packaged as a war file you can deploy and with an Eclipse plug in for designing reports. The plug in has some quirks that I will document in another post.

The web application is fairly straightforward to deploy. I extracted it to birt.war and moved the directory into the deploy directory of JBoss.

You can begin using the application by copying your reports into birt.war in the deploy directory and then use included servlets for display. The following link covers the various servlets (frameset, run, preview, output):

http://www.eclipse.org/birt/phoenix/deploy/viewerUsage2.2.php

That covers linking to reports or running them crudely inside IFrames. If you want tighter integration with your application, BIRT includes a tag library for running reports inside JSPs. It includes two main tags, one which inserts the ajax viewer application and one which inserts the report. Unfortunately, neither passes XHTML validation. The report tag COULD but it has a bug that makes the Javascript free option crash the whole page.

In case you don't need XHTML compliance, just copy the birt.tld file into your application's WEB-INF/tld directory. For example:
liferay-portal.ear/portal-web.war/WEB-INF/tld

If you want XHTML compliance... it gets tougher. The trouble is that you can't put JavaScript inline in an XHTML file because various logic characters are interpreted as XML. What you need then is a JavaScript file you can include that can then work its magic on designed static elements. Rather than rehash the details of the whole file, here it is, birt.js, in all its glory. To use it, just place a div in your XHTML, give it a unique id, and call registerViewer with the ID and report name. Parameters should be included as hidden inputs inside the div. Note, all the hackery you see inside this file is because the IE people can't seem to get anything right, so I had to throw all sorts of hacks in to make it work (like resizing an IFrame doesn't work unless its inside a table):


/* BIRT report loader for XHTML
Loads BIRT reports into IE and FF using XHTML compliant code.
Create a DIV with an ID. Inside the DIU, place a script tag that calls registerReportViewer
*/

if(document.all)
window.attachEvent('onload',loadViewers);
else
window.addEventListener("load",loadViewers,false);

var reportViewers = new Array();

function registerReportViewer(divId, reportFileName) {
if(divId==null || reportFileName==null)
alert('registerReportViewer: A required parameter was null');
else
reportViewers[reportViewers.length]=new Array(divId, reportFileName);
//loadViewer('birtViewer','nr');
}

function loadViewers() {
for(i=0; i<reportViewers.length; i++) {
loadViewer(reportViewers[i][0], reportViewers[i][1]);
}
}

function loadViewer(viewerId, reportfile){
var divObj = document.createElement( "DIV" );
var bodyObj = document.body;
if( !bodyObj )
bodyObj = document.createElement("BODY");
bodyObj.appendChild( divObj );
divObj.style.display = "none";
var formObj = document.createElement( "FORM" );
divObj.appendChild( formObj );
var paramContainer = document.getElementById(viewerId);
if(paramContainer==null)
alert('Couldnt find element with id '+viewerId);
var oParams = paramContainer.getElementsByTagName('input');
if( oParams )
{
for( var i=0;i<oParams.length;i++ )
{
var param = document.createElement( "INPUT" );
formObj.appendChild( param );
param.TYPE = "HIDDEN";
param.name= oParams[i].name;
param.value= oParams[i].value;
}
}
var reportTable = document.createElement( "TABLE" );
reportTable.name=viewerId+"_iframe_table";
reportTable.id=reportTable.name;
reportTable.width="100%";
reportTable.style.border="0px";
var reportTBody = document.createElement ("TBODY"); // required by IE only, doesn't hurt FF
var reportRow = document.createElement( "TR" );
var reportCell = document.createElement( "TD" );
reportRow.appendChild(reportCell);
reportTBody.appendChild(reportRow);
reportTable.appendChild(reportTBody);

var reportIFrame = document.createElement("IFRAME");
reportIFrame.name = viewerId+"_iframe";
reportIFrame.id = reportIFrame.name;
reportIFrame.scrolling="no";
reportIFrame.frameBorder="0";
reportIFrame.style.height = "100%";
reportIFrame.style.width = "100%";
reportIFrame.style.border="0px";
reportIFrame.parentName = reportTable.name;
reportCell.appendChild(reportIFrame);
paramContainer.appendChild(reportTable);

// Resize the iframe to be the same size as the content, attach onload events for each browser
if(window.addEventListener) // Mozilla, FF, NS
reportIFrame.addEventListener('load', resizeEvent, false) ;
else // IE
reportIFrame.attachEvent("onreadystatechange", resizeEvent );

// Submit the form
formObj.action = "/birt/preview?__format=html&__report="+reportfile+".rptdesign&__masterpage=true";
formObj.method = "post";
formObj.target = reportIFrame.name;

// Bug fix for IE: IFrames created by JavaScript don't actually have a "name" in IE's internals
if(document.all) {
if(self.frames[reportIFrame.id].name!=reportIFrame.name) /* THIS IS A BUG FIX FOR IE: TARGET DOESNT WORK WITH JAVASCRIPT CREATED IFRAMES */
self.frames[reportIFrame.id].name = reportIFrame.name;
}
formObj.submit( );
}

function resizeEvent(evt) {
var ieKey = "srcElement";
var mozKey = "currentTarget";
var IFrameObj;
evt[mozKey] ? IFrameObj = evt[mozKey] : IFrameObj = evt[ieKey];
fitIframe(IFrameObj);
}

function fitIframe(IFrameObj) {
var IFrameDoc;
if (IFrameObj.contentDocument) {
// For NS6
IFrameDoc = IFrameObj.contentDocument;
IFrameObj.style.height=IFrameDoc.height+"px";
//alert('detected NS6');
} else if (IFrameObj.contentWindow) {
// For IE5.5 and IE6
IFrameDoc = IFrameObj.contentWindow.document;
if(IFrameDoc.body!=null) { // the IE event fires too often, and fires before IFrame is loaded, in which case doc==null. It fires AGAIN once it loads fully, so ignore the first time
try {
var table = document.getElementById(IFrameObj.parentName);
} catch (e) { alert('IE5.5+: Unable to located IFrames parent table: '+IFrameObj.parentName ); }
try {
var height=parseInt(IFrameDoc.body.clientHeight)+20;
table.style.height=height;//-IFrameDoc.body.offsetHeight;//+"px"; //IFrameDoc.body.scrollHeight-IFrameDoc.body.offsetHeight;
} catch (e) { alert('IE5.5+: Unable to get size of IFrame: '+IFrameObj.name ); }
} // if IFrameDoc!=null

} else if (IFrameObj.document) {
// For IE5
IFrameDoc = IFrameObj.document;
// document.getElementById("birtViewer_div").style.height=IFrameDoc.height;
try {
document.getElementById(IFrameObj.parentName).style.height=IFrameDoc.body.scrollHeight-IFrameDoc.body.offsetHeight;
} catch (e) { alert('IE 5.0: Unable to located IFrames parent table or get size of IFrame: '+IFrameObj.parentName ); }
//alert('detected ie5. IFrame body height:'+IFrameDoc.body.offsetHeight);
//IFrameObj.height="600"; //IFrameDoc.body.scrollHeight; //offsetheight works too
} else {
alert('fitIframe was unable to detect the browser version');
return true;
}
}


No comments:

Labels

Blog Archive

Contributors