Tuesday, December 01, 2009

BIRT Designer Classpath Changes

Starting with the 2.5.2 branch of BIRT (Release date February 2010), configuring the classpath for the designer has been improved. This classpath setting is used by the BIRT engine when processing reports that use Java event handlers or make calls to external classes while in the designer. In previous releases of BIRT, the engine would add all Java projects within the same workspace to the classpath automatically. With BIRT 2.5.2 you will now be able configure the BIRT classpath globally or project specific. This setting is available in the preferences.



In this example I have configured a project (BIRT Reports) to add the BirtEventHandlers Java project to the classpath that the BIRT engine uses when previewing the reports in the designer. Note these changes only affect the designer and you should deploy your event handler classes to the scriptlib directory in the deployed environment. More details are available in the bugzilla entry.

Friday, November 20, 2009

Accessing Spring Beans from the BIRT Designer

Recently I have described methods that can be used to access Spring Beans from the BIRT Engine. These examples are intended to be illustrative and not comprehensive.

More on BIRT and Spring

Calling Spring Objects from BIRT Expressions and Event Handlers

In both of these examples I used the BIRT engine to retrieve Spring objects within the scripting environment. In this post I am supplying an example that illustrates how to implement your own menu in the expression builder, so Spring objects can be called within the BIRT Designer. This will allow you to test your report prior to deployment.

In this post:
BIRT 2.3.1 - Adding Functions to the Expression Builder
I described how to implement the org.eclipse.birt.core.ScriptFunctionService. The attached example is an implementation of this extension point. When using this example the expression builder will appear as follows.



Notice that there is now a SpringFunctions sub-category, which provides one method callBean. This method takes a bean name and a method name and expects a returned string. To keep the example simple no arguments are supported and the method must return a string. The plugin.xml looks like the following:



Provided with the example is a deployable J2EE application and the plugin that implements the ScriptFunctionService. See the readme for details on setting up the example. Also note that the deployable plugin is also attached in the example. You will need to add this to your designer and your runtime. This example works with both the Open Source BIRT designer and the Actuate BIRT designer.

Also included is an example report with the following output.


This example is available at Birt-Exchange.

Friday, November 13, 2009

It's Movember

Movember, that time of year when the days grow shorter, the weather grows colder and the family gathers today for the holidays.  Of course in my family the kids are looking at me and laughing, and I am getting 'that' look from Gretchen my wife.

Yes I am growing in a mustache in an effort to change the face of men's health.  To quote my team lead (I am a part of Team Fat Cyclist).

"Movember is the month formerly known as November. During this month, men — manly men — grow mos as a way to call attention to themselves (hey, I’m just being honest here). 
Then, when people ask you “Why are you growing a moustache?” — and they will ask you this question — you tell them about the cancers affecting men, and ask them to donate to your Mo donation page (the money will be channeled to the Prostate Cancer Foundation and to LiveStrong). 
So really, a mo is kinda like wearing a pink ribbon for breast cancer awareness. But a lot more personal. And harder to remove. And it’s displayed a lot higher."
-The Fat Cyclist (Elden Nelson)

If you are interested in supporting me and helping to raise money for men's health issues, please visit my mo page and donate.

If not me, please visit another great team, the Eclipse Momitters.

Thursday, November 12, 2009

More on BIRT and Spring

In my previous post I discussed calling Spring objects within a BIRT report. That example used an architecture similar to the simplified diagram below.



The Spring Context was injected in the BIRT app context and this gave the BIRT scripting environment access to the Spring Beans. This example could have been expanded further to the Open Source BIRT Viewer by adding a similar object to the Application Context for the BIRT Viewer. See this wiki page for more details. If you use the method described in the wiki page, you may prefer to implement this with a Spring RequestContextFilter.

The simplified architecture for this setup is presented below.



Another option is to use Spring Remoting and the Open Source BIRT Viewer tag libraries or standard URL integration. In this case you add the Spring jars to the WEB-INF/lib of the viewer and write a wrapper class for the Spring remote client. The wrapper class and Spring configuration file can then be added to the WEB-INF/lib directory of the Viewer to access your remote beans. The architecture for this setup would be as follows. Attached to this post is an example of this method.



If you are using the Actuate Java Components technology, you can use the JSAPI within a standard HTML page or generate it in a Spring View which will include the BIRT report. This approach allows Flash charts to be populated by Spring Beans and report interactivity like dynamically grouping, sorting and filtering all without re-executing the report.



The example, that is attached to this post, is a very simple Spring Remoting example. It contains two ANT projects, one for the server application and one that acts as the remote client wrapper. Once you download the example, build the server application and deploy it. Instructions are in a readme file. Then build the client wrapper jar and deploy it as described in the readme. The readme illustrates deploying to the Open Source BIRT Viewer or the Actuate Interactive Viewer. The example uses Spring HTTP Remoting, but any of the Spring Remoting technologies should work. An example report is provided for both deployed environments. Whether you are using the Open Source BIRT Report designer or the Actuate BIRT Designer, the expression to access the Spring Bean will be similar to the following.



Output for the example is as follows.

Open Source Viewer


Actuate Interactive Viewer


The Example is available at BIRT Exchange.

Thursday, November 05, 2009

Calling Spring Objects from BIRT Expressions and Event Handlers

Several examples are already available on the web, which demonstrate calling the BIRT engine from a Spring MVC application.

Integrating BIRT with Spring in a Web application
and
Eclipse BIRT in Spring web applications
are a couple of examples.

There is not much information on how to include Spring Beans within a report design. This post details an example of injecting the Spring ApplicationContext into BIRT’s AppContext object which will allow you to call your Spring Beans in BIRT expressions or event handlers. A link for the source is listed at the bottom. A readme file containing instructions for building the example is included in the download.

You can include the BIRT runtime by following the post above or examining the download. The Example implements a Spring Controller with the following code.


package org.eclipse.birt.spring;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.birt.report.engine.api.HTMLRenderOption;
import org.eclipse.birt.report.engine.api.HTMLServerImageHandler;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class BirtController extends AbstractController {

private IReportEngine reportEngine;

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {

String reportName = request.getParameter("ReportName");
ServletContext sc = request.getSession().getServletContext();
reportEngine = BirtEngine.getBirtEngine(sc);
IReportRunnable runnable = null;
runnable = reportEngine.openReportDesign( sc.getRealPath("/Reports")+"/"+reportName );
IRunAndRenderTask runAndRenderTask = reportEngine.createRunAndRenderTask(runnable);

HTMLRenderOption options = new HTMLRenderOption();
options.setOutputFormat("html");
options.setOutputStream(response.getOutputStream());
options.setImageHandler(new HTMLServerImageHandler());
options.setBaseImageURL(request.getContextPath()+"/images");
options.setImageDirectory(sc.getRealPath("/images"));
runAndRenderTask.setRenderOption(options);
runAndRenderTask.run();

return null;
}

}


Note that no error checking is implemented in this example. This controller class just extends the Spring AbstractController class passes the response object to the BIRT engine to output the report. The report name is retrieved from the request. Before running the report the BirtEngine class is used to retrieve the BIRT engine. This is virtually the same BirtEngine class used in the servlet example available in the BIRT wiki with some exceptions that are noted here.


package org.eclipse.birt.spring;

import java.io.InputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;

import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.IReportEngine;
import javax.servlet.*;
import org.eclipse.birt.core.framework.PlatformServletContext;
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 org.springframework.context.ApplicationContext;

public class BirtEngine {

private static IReportEngine birtEngine = null;

private static Properties configProps = new Properties();

private final static String configFile = "BirtConfig.properties";

public static synchronized void initBirtConfig() {
loadEngineProps();
}
public static synchronized IReportEngine getBirtEngine(ServletContext sc) {
if (birtEngine == null)
{
//optionally load engine props
//loadEngineProps();
EngineConfig config = new EngineConfig();
if( configProps != null){
String logLevel = configProps.getProperty("logLevel");
Level level = Level.OFF;
if ("SEVERE".equalsIgnoreCase(logLevel))
{
level = Level.SEVERE;
} else if ("WARNING".equalsIgnoreCase(logLevel))
{
level = Level.WARNING;
} else if ("INFO".equalsIgnoreCase(logLevel))
{
level = Level.INFO;
} else if ("CONFIG".equalsIgnoreCase(logLevel))
{
level = Level.CONFIG;
} else if ("FINE".equalsIgnoreCase(logLevel))
{
level = Level.FINE;
} else if ("FINER".equalsIgnoreCase(logLevel))
{
level = Level.FINER;
} else if ("FINEST".equalsIgnoreCase(logLevel))
{
level = Level.FINEST;
} else if ("OFF".equalsIgnoreCase(logLevel))
{
level = Level.OFF;
}

config.setLogConfig(configProps.getProperty("logDirectory"), level);
}
config.setEngineHome("");

IPlatformContext context = new PlatformServletContext( sc );
config.setPlatformContext( context );
config.getAppContext().put("PARENT_CLASSLOADER", BirtEngine.class.getClassLoader());
ApplicationContext sprCtx = ContextAccess.getApplicationContext();
config.getAppContext().put("spring",sprCtx);
try
{
Platform.startup( config );
}
catch ( BirtException e )
{
e.printStackTrace( );
}

IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject( IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY );
birtEngine = factory.createReportEngine( config );
}
return birtEngine;
}
public static synchronized void destroyBirtEngine() {
if (birtEngine == null) {
return;
}
birtEngine.destroy();
Platform.shutdown();
birtEngine = null;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
private static void loadEngineProps() {
try {
//Config File must be in classpath
ClassLoader cl = Thread.currentThread ().getContextClassLoader();
InputStream in = null;
in = cl.getResourceAsStream (configFile);
configProps.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

This class just wraps access to the BIRT engine in a singleton.
The notable changes are in these lines of code deal with the EngineConfig class.

config.setEngineHome("");

IPlatformContext context = new PlatformServletContext( sc );
config.setPlatformContext( context );
config.getAppContext().put("PARENT_CLASSLOADER", BirtEngine.class.getClassLoader());
ApplicationContext sprCtx = ContextAccess.getApplicationContext();
config.getAppContext().put("spring",sprCtx);


The setEngineHome is passed a blank value and setting the PlatformContext to use a PlatformServletContext class will by default look for the BIRT plugins in the WEB-INF/Platform/plugins directory. Next we set the parent classloader for the report engine plugin so that classes available to the project will also be available to the BIRT engine. The final line gets the Spring ApplicationContext instance and loads it into the BIRT AppContext object and names it “spring”. The method used for retrieving the Spring context is described in a great post here.

The ContextAccess class is defined as follows.


package org.eclipse.birt.spring;
import org.springframework.context.ApplicationContext;
public class ContextAccess {
private static ApplicationContext ctx;
public static void setApplicationContext(ApplicationContext applicationContext) {
ctx = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}


This Class just contains methods to set and get the static variable ctx, which will contain the Spring ApplicationContext with the addition of one more class.



package org.eclipse.birt.spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


public class SpringContextProvider implements ApplicationContextAware {
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
ContextAccess.setApplicationContext(ctx);
}
}



This Class implements the ApplicationContextAware interface which causes the Spring framework to callback this class with the Spring context, when it is created. The Spring configuration file for this example looks like the following.

<beans>
<bean id="springContextProvider" class="org.eclipse.birt.spring.SpringContextProvider">
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/runbirt.htm">birtController</prop>
</props>
</property>
</bean>
<bean id="birtEngine"
class="org.eclipse.birt.spring.BirtEngine"
destroy-method="destroyBirtEngine">
</bean>
<bean id="birtController"
class="org.eclipse.birt.spring.BirtController">
</bean>
<bean id="carPojo"
class="org.eclipse.birt.spring.CarPojo">
</bean>

</beans>

We have a carPojo bean that is available. To access this from a BIRT expression, all we have to do is use the following syntax.


var mypojo = spring.getBean("carPojo");


You can then call the methods on the object. Eg mypojo.getYear();



Output for the example is presented below.




Caveats
If you preview the report in the designer the report will not work. This is because the Spring context is not available to the designer. The report has to be deployed to test it. There are many ways this example could be extended to circumvent this issue. BIRT provides an extension point to enhance the expression builder which could be used with Spring Remoting to access the Spring context. BIRT also provides an extension to implement a BIRT application context object within the designer that could be used in this same fashion. I will try to implement one of these methods in the future to illustrate this concept.

The example can be downloaded from Birt-Exchange.

Tuesday, October 20, 2009

Multiple Hyperlinks on BIRT Charts

BIRT 2.5.1 was released a couple of weeks ago and with its release BIRT Charts now support multiple hyperlinks. To use this feature select any of the interactivity locations within the chart builder. Next select the add button under the hyperlinks list box.



This will launch the hyperlink editor.



Enter the name you wish to appear in the context menu. Next select the edit base URL button, which will display the Hyperlink Options editor.



Here you have the option to link to a URI, a bookmark within the same report or to a bookmark in another report. Values from the current chart can be passed through to the target. For example the value of a slice could be passed to a google query. To do this select the URI radial and enter an expression similar to the one shown in the image below.



When running the report containing the chart, the multiple hyperlinks menu will popup on whatever event you defined in the editor. In the above example this was defined on a mouse click event. So clicking on a slice of the pie will cause the multiple hyperlinks context menu to appear.



This sample report is available at Birt-Exchange.

Monday, September 28, 2009

Calling BIRT reports from Wicket using Actuate’s JSAPI

I have written several posts on how to use the Actuate JSAPI to integrate with various frameworks. In this post I will detail integrating with Wicket. For more information on the JSAPI see this post:

Showing BIRT Reports using the Actuate JSAPI

Wicket can call BIRT reports with the JSAPI in a similar fashion as other front end frameworks that allow AJAX based APIs, where JavaScript is just embedded into the HTML. An HTML file based on the Hello World Wicket example may look similar to the following.

<html>
<head>
<title>Actuate JSAPI Wicket Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Viewer creation example</title>
</head>
<body>
<b>
<span wicket:id="message">message will be here</span>
</b>

<div id="acviewer" />

<div id="jsapi_example_container"><script type="text/javascript"
src="http://localhost:8080/ActuateJavaComponent/jsapi"></script> <script
type="text/javascript" language="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);
run();
}
Using a Wicket Behavior to write out this code
function run()
{
viewer.setParameters({"Customer":"CAF Imports"});
viewer.setReportName("/Public/BIRT and BIRT Report Studio Examples/Customer Order History.rptdesign");
viewer.submit();
}

</script></div>
</body>
</html>

This example will look very familiar to other examples in the JSAPI overview post. The only real difference is the addition of the wicket message, which is generated by my instance of the Wicket Web Page class. You will notice that the run JavaScript function is hard coding the report name and parameters. This may be something you want to handle in the Java code, to make it more dynamic. One way of handling this is to use Wicket Behaviors to create custom components. You could use a Behavior to write out all the above JavaScript, but we will keep it simple and just write out the run script. So the first thing to do is to create a class that extends the AbstractBehavior class.


package jsapi.wicket.sample;

import org.apache.wicket.Component;
import org.apache.wicket.Response;
import org.apache.wicket.behavior.AbstractBehavior;
import org.apache.wicket.util.string.JavascriptUtils;

public class ReportComponent extends AbstractBehavior{

private static final long serialVersionUID = 1L;

public void onRendered(Component component) {
Response response = component.getResponse();
response.write(JavascriptUtils.SCRIPT_OPEN_TAG);
response.write("function run(){");
response.write("viewer.setParameters({\"Customer\":\"CAF Imports\"});");
response.write("viewer.setReportName(\"/Public/BIRT and BIRT Report Studio Examples/Customer Order History.rptdesign\");");
response.write("viewer.submit();}");
response.write(JavascriptUtils.SCRIPT_CLOSE_TAG);
}

}


This class overides the onRendered method to write out the entire run script from the HTML above. I can now modify my extended WebPage class to add an instance of the ReportComponent class.


package jsapi.wicket.sample;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class ReportParameter extends WebPage {

private static final long serialVersionUID = 1L;

public ReportParameter(final PageParameters parameters) {

// Add the simplest type of label
Label myLabel = new Label("message", "Actuate JSAPI Wicket Example");
add(myLabel);
ReportComponent rc = new ReportComponent();
myLabel.add(rc);
}
}


The script is written below the Label component.
Finally the HTML should have the run JavaScript function commented out. The output from this example is as follows.


The generated HTML looks like:



Note that you can use the built in view time functions like selecting new parameters and rerunning the report without any additional code.



The example files can be downloaded from Birt-Exchange.