Home
Analytics
Generating PDF report using Report Engine API
jyol2005
I am using Report Engine APIs to set the data object on the report:
task.getAppConext().put("dataObj", myObj);
In the dataset's open and fetch methods, I'm accessing this object.
When I run this as a standalone application, everything is working fine, but when I do this from a Servlet and deploy it on WebLogic, the report is generated, but the table doesn't have any rows. I debugged the application and looked at the task's appContext and it has the data object with all the records.
I'm generating PDF report (in the servlet) with the below options:
options = new PDFRenderOption();
options.setOutputFormat("pdf");
options.setOption("AllowModification", Boolean.valueOf(false));
response.setHeader("Content-type", "application/pdf");
options.setOutputStream(response.getOutputStream());
task.setRenderOption(options);
The report does get generated and all the text labels, etc. that I replace using Design Engine APIs get displayed properly. Not sure why there is no data in the table.
Please help!
Find more posts tagged with
Comments
JasonW
Can you post the report design?
Jason
jyol2005
Jason,
Thanks for the response. Attached is the rptdesign file. This works well if I implement as a standalone Java application, but the same rptdesign produces a blank table when I integrate with my framework and deploy in our web application.
Thanks.
JasonW
What class type is the calrow and is this type in the classpath?
In your open method drop some code in like this after the totalrows variable is populated:
importPackage( Packages.java.io );
out = new PrintWriter( new FileWriter( "c:/temp/mysds.txt", true ) );
out.println( "cal size = " + totalrows);
out.close();
Jason
jyol2005
calrow is an instance of CALData which is a POJO.
I added the three lines you gave in open() and the following line in fetch() as CALData is in this package:
importPackage( Packages.reports.custacctlist );
I see cal size = 282 printed in the mysds.txt, but today I don't even see the report coming up. I don't see any errors/exceptions in the log (I have set the log level to FINE), but no PDF report is visible.
jyol2005
I resolved the issue with the report not coming up. It is coming up and cal size = 282 is logged, but still no data in the table.
JasonW
if you put the same code in the fetch and just put the row count do you see any rows being called?
Jason
jyol2005
In fetch(), I'm printing the totalrows, currentrow and account # in the current row. Here's what I get, but still no data in the table.
total rows = 282
row: 0 actno.: 896-01488
total rows = 282
row: 1 actno.: 896-01489
total rows = 282
row: 2 actno.: 896-01490
........
I must be missing something. In data binding, I see dataSetRow, but in fetch(), I'm assigning to row. Is this correct?
<list-property name="boundDataColumns">
<structure>
<property name="name">accountNumber</property>
<property name="displayName">Account Number</property>
<expression name="expression">dataSetRow["accountNumber"]</expression>
<property name="dataType">string</property>
</structure>
......
fetch():
importPackage( Packages.com.bear.srvcms.reports.custacctlist );
calrow = CustActDataVec.get(currentrow);
row["accountNumber"]=calrow.accountNumber;
JasonW
Can you make a copy of the report and delete all the report items on the canvas but the table that is bound to the scripted ds and run it? Also in the fetch that you printed out did it show all the rows? I checked the data binding and how you are implementing fetch and it all looks good. I am just wondering if you are getting a null object on one of those rows.
Jason
jyol2005
The account # is printed 282 times (from row 0 to 281) and I didn't see any null values. In fact, I printed all the fields for each record and there are no null values anywhere. This report is working fine when I run outside the web environment which is confusing.
JasonW
This is confusing :>
Can you try to make a copy of the report and with the copy delete all elements on the report canvas and just drag the one dataset to the canvas?
Jason
jyol2005
Jason,
I'M SO SORRY, but I am setting sorting on the table using APIs and I had row["ACCOUNTNUMBER"] instead of row["accountNumber"] as the sort key. It doesn't throw any exception or indicate any error and I couldn't figure it out.
Once I corrected this, it's working fine now. I'm able to see all the data.
Again, I really apologize for my oversight of this.
Thank you very much for being patient and for all the help.
JasonW
No problem, glad its working.
Jason
jyol2005
Jason,
Now that I've got a feeling for BIRT scripted data source/set and engine APIs, I was wondering if what I'm doing is the right way.
These are the steps I've to do for each report:
1. Create a scripted data source
2. Create a scripted data set and manually add all the output columns.
3. Layout the report in the designer using these columns
4. Using REAPI and DEAPI, replace all the dynamic text and pass the data object (retrieved and formatted in our application)
5. Using open, fetch and close methods of the data set, access the data object from the context.
6. Generate the PDF/Excel report using REAPI.
Is there a better approach?
Thanks a lot.
JasonW
I am not sure what this step is
Using REAPI and DEAPI, replace all the dynamic text and pass the data object (retrieved and formatted in our application)
but simpler is always better IMO. One thing you could do is put your scripted datasets in a lib, so they can be reused.
Jason
jyol2005
setting label values like report title, subtitle, etc. dynamically using:
protected void setLabel(ReportDesignHandle report, String name, String value) {
try {
DesignElementHandle deh = report.findElement(name);
if (deh instanceof TextItemHandle) {
TextItemHandle tih = (TextItemHandle) deh;
tih.setContent(value);
} else if (deh instanceof LabelHandle) {
LabelHandle lh = (LabelHandle) deh;
lh.setText(value);
}
} catch (Exception e) {
}
}
and passing data obj using REAPI:
task = birtReportEngine.createRunAndRenderTask(design);
task.getAppContext().put("dataObj", mydata);
Scripted dataset is different Java object for each report.
jyol2005
I have a table with two table headers (column headers) and depending on some condition, I need to show/hide each one of these. It's working fine on the first page, but the visibility logic doesn't get executed at the page break and both headers appear. Is there anyway to only show one header depending on some condition, either at design time or at run time.
Thanks.
jyol2005
I have created a different report (it's little more complicated) with 2 groups and conditional headers/footers, etc. The report comes up fine, but again no data in the report. I have set the logger level to FINE, but still don't see any issues. I have added some debug statements in the script dataset's open method, but nothing gets printed. I know that there are 41 rows in the data object I'm passing to the report, but nothing gets printed. I'm confused.
Can someone please help me?
I have attached the report design here. I'm using a report library, but I'm unable to attach it here.
JasonW
If you just put a table at the top of the report that is tied to the scripted dataset does it show up?
Jason
jyol2005
I took away everything and just kept the table. Initially, it still didn't generate the table, but that's because I was trying to set the values for the labels of report title, etc. which I removed. After I corrected all these and changed row[] to dataSetRow[] in fetch() script, it's working fine. Now, I am trying to add one at a time and generate the report.
I had posted previously regarding conditional table headers (column headers). I have two table headers and I need to hide/show one of them depending on some condition. This logic works fine initially, but after page break, it displays both. On first page, I want to show table hdr 1 and second page, hdr 2. What is the proper way of show/hide table headers?
Thanks.
JasonW
The problem is that the table header rows are only evaluated once. To get around this put the same table in twice and put different headers in each. Then add a computed column to the dataset that tracks a running count of rows. Apply filters to both tables and use the rowcount you created to show only a certain number of rows in the first table and the rest in the second table. Usually you want the filter in the first table to match the page break interval for the table. Take a look at the attached example. Another option is if you are grouping and doing a page break for every group the group headers would be evaluated evey page which you could then use the normal visibility method.
Jason
jyol2005
Jason,
Thank you very much for the suggestion you've provided with the groups. In fact, I have 3 groups and the table header changes when the first group by column value changes (it can only take two values - LONG, SHORT)
So, for the first group, I have two group headers with visibility property set to compare the value of the group by column. These group headers work as my table header and it works perfectly.
I have a table header which only shows up if there is no data (it's a requirement to show the table header with No Data label below that) with visibility expression set to: Total.count()>=1. This is also working fine. The only issue I have is, I added a second detail row (with static text No Data...) and set the visibility property to same as the table header, but it never shows up when there's no data. Not sure what I'm doing wrong....
JasonW
This makes sense because if there is no data the the detail rows do not get processed. Either add another header row with your label "No Data" with the same visibility expression or set a variable in the first visibility expression say
if (Total.count() < 1){
true;
tableNoData = true;
}else{
false;
tableNoData = false;
}
Then drop a labe after the table that uses the tableNoData as the visibility expression.
Jason
jyol2005
Thanks, Jason. This works like a charm.
Now, I'm having some issues with report parameters. I have set them using report engine api, but when report is generated, the default parameter values are being used.
The following is the code:
Map rpMap = new HashMap(); // I tried the following lines instead of this line:
/*
IGetParameterDefinitionTask paramTask = birtReportEngine.createGetParameterDefinitionTask(design);
rpMap = paramTask .getDefaultValues( );
*/
rpMap.put("multiAcct", true); // default is false
rpMap.put("showQty", false); // default is true
task = birtReportEngine.createRunAndRenderTask(design);
task.setParameterValues(rpMap);
JasonW
That should work fine. Can you post the report design?
jyol2005
Here's the report design.
jyol2005
Jason,
Did you get a chance to look at this? I can't seem to get the parameters to work for me. Not sure what I'm doing wrong.
Also, is there any way to switch the group by column dynamically? The user can choose to group by (between two columns). I have tried creating a group header and footer with data columns both in the header and footer, but didn't assign a binding.
Using DEAPI, I added the below code, but it didn't work:
DataItemHandle grpHdrData = (DataItemHandle) report.findElement("grpHdrData");
DataItemHandle grpFtrData = (DataItemHandle) report.findElement("grpFtrData");
if(glr_parms.groupBy.equals(GROUP_BY_COL_A)) {
grpHdrData.setResultSetColumn("colAData");
grpFtrData.setResultSetColumn("colAData");
}
else if(glr_parms.groupBy.equals(GROUP_BY_COL_B)) {
grpHdrData.setResultSetColumn("colBData");
grpFtrData.setResultSetColumn("colBData");
}
Is this the right approach and if so, what am I doing wrong?
Thanks.
JasonW
I saw nothing in the report that would cause this issue. What version of BIRT are you using?<br />
<br />
For the group change, just use an expression on the group. See this example:<br />
<a class='bbc_url' href='
http://www.birt-exchange.com/devshare/designing-birt-reports/772-change-group-based-on-parameter/#description'>Change
Group Based on Parameter - Designs & Code - BIRT Exchange</a><br />
<br />
Jason
jyol2005
I'm using BIRT 2.3.1. (runtime) and BIRT plugin 2.2.2.
If I can get the report parameters to work (setting using APIs), then the attached group example also would work, right?
JasonW
Correct.
Try
task.setParameterValue("multiAcct", true);
Jason
jyol2005
Jason,
Thanks for your help. task.setParameterValue worked fine and I resolved the dynamic group issue also using that.
I have another question; when I use dynamic text ("Page " + pageNumber + " of " + totalPage) to display page numbers in the footer, it's always showing Page 1 of 1 on all the pages. I don't want to use the Autotext (which is a grid) as I'm having trouble with the formatting.