Tuesday, February 02, 2010

Remus Uses BIRT

I read about the Remus project on Planet Eclipse today and was intrigued.   Looking at the draft project proposal:

With today's information technologies, the amount of information we consume daily is enormous. Efficient management and fast access to frequently used information has become more important than ever. The fact that we use a wide range of applications and digital mediums makes the aggregation of information, search and retrieval even more difficult. Managing a huge amount of information successfully requires an intelligent tool that enables users to file, categorize and visualize such diverse types of data as information units in a single application.
And now I am very intrigued, my company Innovent Solutions works in this very space.  Naturally, I wondered about how BIRT could interact with Remus.  Turns out that they have created an ODA for BIRT and have bundled some reports.  

Looks like another nice use of BIRT.

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?

Friday, December 18, 2009

EclipseCon Submissions - Last Chance to Propose a Talk

Oisín Hurley is one of the smartest, funniest and best looking people in the Eclipse community*  So when he says jump, I jump.

That's right it is the last day to get your EclipseCon submission for a talk in.  If you have been doing anything interesting with BIRT that you would like to share with the Eclipse community, we would love to hear about it.  There are lots of opportunities to present at different lengths.

Head on over to the EclipseCon submission site and make a proposal about how you are using BIRT.


*And totally immune to blatant attempts at flattery.

Monday, December 14, 2009

BIRT Plugins at Google Code

Blackboard, Inc. develops solutions for the K-12 school, college campus, workplace, and community that increase the impact of education by transforming the experience of education. Blackboard has chosen BIRT as its reporting and business intelligence tool.  

Over the last two years I have been lucky to work with Blackboard on their BIRT integration.  Working with their product and developers we have been able to enhance their core product with reports.  Each Blackboard report tells a story that can help their clients better perform their jobs.  

One of BIRT's features that was extremely helpful was the ability to customize and extend BIRT to meet Blackboards requirements.  Using the BIRT extension points we added functions and controls to BIRT that improved both the developer and users experience when interacting with BIRT.

Blackboard has agreed to release some of the generic portions of this work back to the BIRT community as open source contributions.  Rather than rolling these contributions into the core product (where it would quickly get lost amidst all the other code) we have created two small open source projects that can be used by the community.  These projects can be used either as fully functional products or as best practice sample code.  





BIRT Functions
Uses the Aggregate and Script Function extension point to add new functions to the BIRT product.



BIRT Controls
Uses the ReportItem extension point to create new elements that show up on BIRT reports.



Innovent Update Site
Hosts an Eclipse Update site for both projects. We will be adding new projects to this site as we finish up the code.

If you are a BIRT developer that just wants to get started you can use the following update link:
  http://innovent.googlecode.com/svn/trunk/update

If you would like to find out a bit more about the projects, please visit the project sites.


Thanks go out to thank both BIRT Exchange and the brand spanking new Eclipse Marketplace for providing access to our projects.  It is really great to have a couple of quality channels to publicize our work to the BIRT community.

Also, I want to mention the team that helped to build and get this code open sourced.  Steve Schafer from Innovent Solutions wrote a lot of the code and figured out the inner workings of the ReportItem exension point.  Blackboard had a whole team of people working on reports, in particular thanks to Heather, JoAnna, Michelle, Dan, Joe, Joel, and Manpreet.



    Friday, December 11, 2009

    Calling Client Side JavaScript from a BIRT Chart

    A couple of months ago I detailed a new feature for BIRT charts that allows multiple hyperlinks to be attached to one the supported events. That post is available here.

    In this post I will discuss using a BIRT Text element that contains script which executes within the client browser and contains functions that are called from rendered charts.

    General Information
    BIRT currently supports interactivity on many chart components like chart series, title, axis, and the legend. The components that support interactivity will depend on the type of chart being used. The events are client based events like mouse click, mouse over, key down, etc. Multiple events can be hooked and each is associated with an action. Actions define the behavior that should occur when a specific event happens. The actions available depend on what component the action is defined for and what chart output type is being used. Currently BIRT supports the following Actions.

    Hyperlink – Supports multiple hyperlinks, drill through, and linking to bookmarks.
    Show Toolip – Supports displaying tooltips. Data available for use in the tooltip will depend on the component.
    Highlight – Highlights the selected component. Most often used to highlight specific series or data point.
    Toggle Visibility – Toggles the visibility of the selected component. Most often used to change the visibility of a series or data point.
    Toggle DataPoint Visibility – Toggles the data point label visibility.
    Invoke Script – Invokes client side script.

    Additionally if you are using the Chart engine within an SWT, SVG, or Swing based application the engine supports adding a callback action that your code can use to interpret chart events.



    Highlight, Toggle Visibility, and Toggle DataPoint Visibility actions are only available when using an SVG output setting.



    If you use SVG, and you wish to test the report in the designer remember to set the Enable SVG chart in the Preview preferences for the Report Design Preference entry.



    More information on Chart Interactivity is available here. Also see the Chart FAQ for more details.

    InvokeScript Example
    The follow section details an example of using the invokeScript action on multiple Chart events.

    Assume that you have a Chart that displays a set of customers with a series value for each equal to the customer's credit limit.



    Suppose you want to display the customer details right below the chart when the mouse is moved over a specific data point. This can be done using the invokeScript action on the mouse over event for the chart series. To do this first create a table below the chart that is bound to the same dataset that the chart is using. You can then nest a table that calls another data set to retrieve customer information. In the attached example this will be the ChartData and CustomerInformation datasets respectively.



    By default this will generate a inner table that contains customer information for every customer represented in the chart. Obviously you do not want to display all of these at once, so create a new style in the style editor with only one property overridden – Text Block:Display set to no Display. Apply this new style to both the inner and outer tables.



    If you run the report after completing this step all the tables will be generated in the output but none will be displayed. This is different than using the visibility property which will not put the tables in the output. Enter the following bookmarks for the outer and inner tables.

    Outer table bookmark expression: "myoutertable";
    Inner table bookmark expression: "mytable"+row["CUSTOMERNUMBER"]

    This will assign the outer table id to myoutertable and a unique id for each inner table starting with mytable and the customer number for the given inner table appended to it. We can now use these with some client script to turn them on or off.

    Add a Text element below the two tables with the following value.


    <script>
    function clearSel(){
    var ot=document.getElementById("myoutertable");
    ot.style.display="none";
    var intbls=ot.getElementsByTagName("TABLE");
    for( jj=0; jj<intbls.length; jj++ ){
    intbls[jj].style.display = "none";
    }
    }
    function DisplayCustomer(cat) {
    clearSel();
    //alert(cat);
    document.getElementById("myoutertable").style.display="block"
    document.getElementById("mytable"+cat).style.display="block"

    }
    </script>



    Make sure to set the Text type to HTML.

    The clearSel function first finds the outer table and then locates every nested table and sets the display style for each to none. The outer table’s display style is also set to none. This will effectively hide both tables.

    The DisplayCustomer function first clears all current displayed tables. Next it uses a category passed in from the Chart to find the specific customer inner table and sets its display style to block. It also sets the outer table to be visible.

    To link these two functions to the Chart use the Interactivity button on the Value (Y) Series as shown in the picture below. Note that we use a mouse over event to call the DisplayCustomer function and a mouse click function to clear the tables.



    This produces the following output.



    As the mouse is moved over the different tubes the table below the chart will update. To clear the tables click on one of the tubes. You will notice that we passed categoryData to the DisplayCustomer JavaScript function. This is a predefined variable available to the invokeScript function that contains the category value for a specific datapoint. The example report lists the predefined variables and in what action they are available using label elements at the top of the report. These labels are hidden at run time.

    The example is available at BIRT Exchange.