In BIRT if you define a Flat File Data Source you have to provide it with an absolute path, and if you try to cheat by going in to the XML and changing the path to a relative one the data simply won’t be found.
This is very frustrating if you want to ship a set of data with a report, in my case as one of the tests for my Excel Emitters.
The solution is a little bit of scripting in the beforeFactory method:
var path;
if( reportContext.getHttpServletRequest() != null ) {
var request = reportContext.getHttpServletRequest().getParameterMap();
path = request.get( "__report" )[0].toString();
}
if( path!= null){
if( path.contains( "/" ) ) {
path = path.substring( 0, path.lastIndexOf( "/" ) );
} else if( path.contains( "\\" ) ) {
path = path.substring( 0, path.lastIndexOf( "\\" ) );
}
}
// java.lang.System.err.println( "resourcePath = " + path );
this.getDataSource( "Mission Data Source" ).setPrivateDriverProperty( "HOME", path );
That’s great if you are running your report from a normal environment (where reportContext.getHttpServletRequest() will not be null), but what if you are running it from a custom ReportEngine host?
Well, in that case you need to add the path to the report to the appContext:
if( filepath != null ) {
@SuppressWarnings("unchecked")
Map<String,Object> appContext = (Map<String,Object>)reportRunTask.getAppContext();
if( appContext == null ) {
appContext = new HashMap<String,Object>();
reportRunTask.setAppContext(appContext);
}
appContext.put("__report", filepath);
}
Which only leaves the small problem of how to find the correct path to the report design file.
In a normal environment finding the path to the report design file shouldn’t be too difficult, but if the report design is a resource in an OSGi bundle (i.e. in an eclipse plugin unit test) you have a few more hoops to jump through:
String filepath = null;
if( Activator.getContext() != null ) {
URL bundleLocation = new URL(Activator.getContext().getBundle().getLocation());
// System.err.println( "Activator.getContext().getBundle().getLocation() = " + bundleLocation );
String bundleLocationFile = bundleLocation.getFile();
if(bundleLocationFile.startsWith("file:/")) {
bundleLocationFile = bundleLocationFile.substring(6);
}
// System.err.println( "bundleLocationFile = " + bundleLocationFile );
URL resourceLocation = this.getClass().getResource( filename );
String resourceLocationFile = resourceLocation.getFile();
// System.err.println( "resourceLocationFile = " + resourceLocationFile );
filepath = bundleLocationFile + "bin" + resourceLocationFile;
// System.err.println( "filepath = " + filepath );
}
It’s worth having those println method calls in there so you see what you are getting for the bundle and resource location – the values will almost certiainly change with different OSGi hosts, but that works for my plugins unit tests.
And of course, now the beforeFactory script needs modifying to pick up from either the Servlet request or the appContext:
var path;
if( reportContext.getHttpServletRequest() != null ) {
var request = reportContext.getHttpServletRequest().getParameterMap();
path = request.get( "__report" )[0].toString();
} else if( reportContext.getAppContext() != null ) {
path = reportContext.getAppContext().get( "__report" );
}
if( path!= null){
if( path.contains( "/" ) ) {
path = path.substring( 0, path.lastIndexOf( "/" ) );
} else if( path.contains( "\\" ) ) {
path = path.substring( 0, path.lastIndexOf( "\\" ) );
}
}
// java.lang.System.err.println( "resourcePath = " + path );
this.getDataSource( "Mission Data Source" ).setPrivateDriverProperty( "HOME", path );
Recent Comments