Thursday, January 28, 2010

BIRT 2.5 Integration Webinar

For those who attended the Webinar we did this week, I am attaching the slides and examples. They are available at BIRT Exchange. If you did not get a chance to participate, the recording is available at Eclipse Live. The examples illustrate different deployment and use cases and were built using BIRT 2.5.

Thanks Lynn for putting this together.

Friday, January 15, 2010

Using Actuate’s JSAPI with a JBoss SEAM component

If you are using Actuate’s JSAPI to run BIRT reports and you wish to pass parameters from a SEAM component this can be done very easily. In addition you can combine SEAM remoting with the JSAPI to do some interesting things. For example assume we create a SEAM component that retrieves report parameters that we want to use with the JSAPI. The component would look similar to this:



package com.actuate.seam.example;

import org.jboss.seam.annotations.*;
import org.jboss.seam.*;
import org.jboss.seam.annotations.remoting.WebRemote;

@Name("reportParameters")
@Scope(ScopeType.SESSION)
public class ReportParameters {
private String parmName = "";
private String parmValue = "";
public String getParmName() {
return parmName;
}
public void setParmName(String pn) {
this.parmName = pn;
}
public String getParmValue() {
return parmValue;
}
public void setParmValue(String pv) {
this.parmValue = pv;
}
@Create
public void initData() {
setParmName("customer");
setParmValue("CAF Imports");
}
@WebRemote
public String getAlternateReport() {
return "/Public/BIRT and BIRT Report Studio Examples/Top 5 Sales Performers.rptdesign";
}
}



All we have in this class is a report parameter name and value. Obviously the values would not be hard coded but for simplicity they are in this example. We also have one web remote method to retrieve the path of a specific report. We will use this to change the report being rendered via SEAM remoting. The XHTML page would look like the following:




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:s="http://jboss.com/products/seam/taglib">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Seam Remoting - Actuate JSAPI Example</title>
</head>

<body>
<h1>Seam Remoting -Actuate JSAPI Example</h1>
<p></p>
<s:remote include="reportParameters" />

<button onclick="javascript:changeReport()">Change Report</button>
<div id="acviewer" />
<div id="jsapi_example_container">
<script type="text/javascript"
src="http://localhost:8080/ActuateJavaComponent/jsapi">
</script>

<script type="text/javascript">
actuate.load("viewer");
actuate.initialize("http://localhost:8080/ActuateJavaComponent/",
null,
null,
null,
initViewer);
var viewer;
function initViewer()
{
viewer = new actuate.Viewer("acviewer");
var viewerwidth = 800;
var viewerheight = 620;
viewer.setWidth(viewerwidth);
viewer.setHeight(viewerheight);
runInitial();
}
function runAlternate(newReport)
{
viewer.setReportName(newReport);
viewer.submit();
}
function runInitial()
{
viewer.setParameters({"#{reportParameters.parmName}":"#{reportParameters.parmValue}"});
viewer.setReportName("/Public/BIRT and BIRT Report Studio Examples/Customer Order History.rptdesign");
viewer.submit();
}
function changeReport() {
var callback = function(newReport) { runAlternate(newReport); };
Seam.Component.getInstance("reportParameters").getAlternateReport(callback);
}
</script>
</div>
</body>
</html>



We use the standard JSAPI viewer tag to run the report, with the EL-Bindings to retrieve the report parameter name and value when the page is loaded. The page also has a button to change the report. This button uses SEAM remoting to call the getAlternateReport method which returns the path to the new report. The callback function then calls the runAlternate JavaScript method which in turn calls the JSAPI to run the new report. When the page is first loaded the following is displayed.




Notice that the report is executed for CAF Imports, which is the parameter retrieved from the ReportParameters class. Clicking on the change report button will display the following.



This example is based on the SEAM remoting helloworld example. It was tested with JBoss AS 5.1.0 and SEAM 2.2.0. The source for it is available here. To run this example download and extract it to the jboss-seam-2.2.0.GA\examples\remoting directory. If you have already set the application server settings in the SEAM build.properties file, all you should have to do to build the example is type:
Ant explode in the example directory.

If you have downloaded Actuate’s Java Component technology and wish to deploy it to JBoss 5.1.0 GA, you will need to extract the war and remove xercesImpl.jar from the ActuateJavaComponent/WEB-INF/lib directory. Rebuild the WAR and deploy to your JBoss AS.

Wednesday, January 13, 2010

Quick and Dirty Logging

One of the best ways to debug your BIRT Expressions and JavaScript is logging.  I have worked with a number of different techniques for logging, and finally settled on using the script functions to create a logging utility.  This approach can be seen in the birt-functions-lib project.

But I frequently don't have the functions library, and I just want examine a value or an object.  I need quick and dirty logging, not a logging infrastructure.

As you probably know, BIRT JavaScript can interact with Java objects natively.  So I should be able to invoke

java.lang.System.out.println("message");
and see an output message.  There are just two tiny 'tricks' you need to know about to make this work.

First, the Eclipse application that BIRT runs under has a console mode.  To run eclipse in console mode run eclipsec.exe instead of eclipse.exe.  


Second, in order to access the java.lang package you need to preface your method call with the keyword Packages, as in:
Packages.java.lang.System.out.println("message");

As you can see, your message will appear in the console window, quick and dirty.



If you are going to be doing a lot of quick and dirty logging, you can use the importPackage method to clean things up:

importPackage(Packages.java.lang);
System.out.println("message with import package");

You can even create a global function that will wrap off the message generation if you are feeling motivated.

importPackage(Packages.java.lang);
function log(msg){
    System.out.println(msg);
}
reportContext.setGlobalVariable("log", log);

log("Test global function");

But my feeling is that once you have reached that level, it would be just easier to use a script function and allow people to select the function through the UI.  Did I mention that there is an open source functions library that will do this for you?