2014-09-12

Pentaho reports with Java API

Intro

I found very little documentation with examples about how to use pentaho reporting API in Java. Most of the time I had trouble in establishing dependencies necessary to get the pentaho reporting to generate the reports out from the designer generated files with a ".prpt" extension. The story got even more complicated when I tried generating the graphs. The exceptions I encountered had very little solutions available on-line. I've decided for the 5.0.3 version because there are couple of books available that describe how to use that specific version. Moreover gradle seems to be very popular now-days so I decided to list the dependencies with it.

Dependency list

You will find most of the dependencies available on the pentaho repository. It might come as a surprise to you but there are also a lot of other dependencies that have to be included. JFreeChart is the first.

  • "org.jfree:jfreechart:1.0.17"
  • "pentaho-reporting-engine:pentaho-reporting-engine-classic-core:5.0.3"
  • "pentaho-reporting-engine:pentaho-reporting-engine-classic-extensions:5.0.3"
  • "pentaho-reporting-engine:pentaho-reporting-engine-classic-extensions-xpath:5.0.3"
  • "pentaho-reporting-engine:pentaho-reporting-engine-legacy-charts:5.0.3"
  • "pentaho-library:libloader:5.0.3"
  • "pentaho-library:libxml:5.0.3"
  • "pentaho-library:libserializer:5.0.3"
  • "pentaho-library:libformula:5.0.3"
  • "pentaho-library:libfonts:5.0.3"
  • "pentaho-library:libformat:5.0.3"
  • "pentaho-library:libdocbundle:5.0.3"
  • "pentaho-library:libswing:5.0.3"
  • "pentaho-library:flute:5.0.3"
  • "pentaho-library:libcss:5.0.3"
  • "pentaho-library:libpixie:5.0.3"
  • "pentaho-library:libsparkline:5.0.3"
  • "pentaho-library:libbase:5.0.3"
  • "pentaho-library:librepository:5.0.3"
  • "com.lowagie:itext:2.1.7"
  • "com.lowagie:itext-rtf:2.1.7"
  • "org.apache.poi:poi:3.9"
  • "org.apache.poi:poi-ooxml:3.9"
  • "bsf:bsf:2.4.0"
  • "rhino:js:1.6R7"
I hope this list will save somebody some time. It took me a while to compile it. The last one was a particularly time intensive to find. I found It thanks to the following post: http://forums.pentaho.com/archive/index.php/t-152813.html


Generating reports from .prpt files

If you ever come across this text you probably won't have trouble loading the MasterReport from the file system or some similar source. In my humble opinion the most complicated output format is actually the HTML. In order to get everything to work I had to extend the HtmlPrinter class. Other methods of including graphs were not an option so I had to include the images as Base64

Extending the HtmlPrinter:

        public class YourSuperPrinter class extends HtmlPrinter {

        // constructor
        super(resourceManager);

        // override print
        super.print(logicalPageKey, logicalPage, contentProducer,
            metaData, incremental);

        // we'll need convert the Image to BufferedImage
        private static BufferedImage toBufferedImage(Image img) {
            if (img instanceof BufferedImage) {
                return (BufferedImage) img;
            }

            BufferedImage bimage = new BufferedImage(
                img.getWidth(null), img.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);

            Graphics2D bGr = bimage.createGraphics();
            bGr.drawImage(img, 0, 0, null);
            bGr.dispose();

            return bimage;
        }

        // override writeImage
        if (image instanceof DefaultImageReference) {
            DefaultImageReference dir = (DefaultImageReference) image;

            if (dir.getImage() != null && encoderType != null) {
                BufferedImage img = toBufferedImage(dir.getImage());

                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageIO.write(img, 
                    encoderType.substring(encoderType.indexOf("/") + 1),
                    baos);
                baos.flush();
                byte[] imageInByte = baos.toByteArray();

                String imageData = Base64.encode(imageInByte);

                return "data:" + encoderType + ";base64," + imageData;
            }
            else {
                return dir.getSourceURLString();
            }
        }

        return super.writeImage(image, encoderType, quality, alpha);
    

Now that you have your Super printer you can generate html:

        MasterReport rep;
        AbstractReportProcessor reportProcessor;

        // BEGIN HTML specific
        StreamRepository tp = new StreamRepository(outputStream);
        ContentLocation tr = tp.getRoot();
        HtmlOutputProcessor op = new StreamHtmlOutputProcessor(
            rep.getConfiguration());
        HtmlPrinter printer = new YourSuperPrinter(
            rep.getResourceManager());

        printer.setContentWriter(tr, 
            new DefaultNameGenerator(tr, "index", "html"));
        printer.setDataWriter(null, null);
        printer.setUrlRewriter(new FileSystemURLRewriter());

        op.setPrinter(printer);

        reportProcessor = new StreamReportProcessor(rep, op);
        // END HTML specific

        reportProcessor.processReport();

        outputStream.close();
        outputStream.flush();
    

If everything went fine you should be generating super graphics and charts in your reports.

Let's mention other report formats together with their specifics:

Excel

        FlowExcelOutputProcessor target = new FlowExcelOutputProcessor(
            rep.getConfiguration(), outputStream, 
            rep.getResourceManager());
        reportProcessor = new FlowReportProcessor(rep, target);

        // if you want to download the file
        response.setContentType("application/vnd.ms-excel");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.xls");
    

PDF

        PdfOutputProcessor outputProcessor = new PdfOutputProcessor(
            rep.getConfiguration(), outputStream, 
            rep.getResourceManager());
        reportProcessor = new PageableReportProcessor(
            rep, outputProcessor);

        // if you want to download the file
        response.setContentType("application/pdf");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.pdf");
    

CSV

        StreamCSVOutputProcessor outputProcessor = 
            new StreamCSVOutputProcessor(outputStream);
        reportProcessor = new StreamReportProcessor(rep, outputProcessor);

        // if you want to download the file
        response.setContentType("text/csv");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.csv");
    

RTF

        StreamRTFOutputProcessor outputProcessor = 
            new StreamRTFOutputProcessor(
            rep.getConfiguration(), outputStream, 
            rep.getResourceManager());
        reportProcessor = new StreamReportProcessor(rep,
            outputProcessor);

        // if you want to download the file
        response.setContentType("application/rtf");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.rtf");
    

XML

        // no .processReport here, just stream close and flush ...
        XmlTableReportUtil.createStreamXML(report, outputStream);
        outputStream.close();
        outputStream.flush();

        // if you want to download the file
        response.setContentType("application/xml");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.xml");
    

TEXT

        // no .processReport here, just stream close and flush ...
        PlainTextReportUtil.createPlainText(report, outputStream);
        outputStream.close();
        outputStream.flush();

        // if you want to download the file
        response.setContentType("application/text");
        response.addProperty(
            "Content-Disposition", "attachment; filename=hello.txt");
    

I hope this post will help somebody, It took me a while to figure all this out.

5 comments:

Anonymous said...

Hi Marko, you got an interesting post on how to get chart appearing from a PRPT file using Reporting Engine SDK with output text/html. I'm still having trouble get any charts to show up from my "working" PRPT file and SDK only output its table data. PRPT worked OK in PRD 5.2. My SDK is all upgraded to using 5.2 JARs. I incl the missing JARs u stated. My run has no errors, no charts when running from Eclipse IDE using Tomcat 7.0.

I haven't tried your SuperPrinter class for HTML output becoz I dont understand how to compile your class SuperPrinter. IDE is giving all kinds of syntax error of this class.

Are you able to post the complete class file of SuperPrinter for me?

I m beginning to sense guys from Pentaho are short-cutting us that the SDK will display charts. They dont even have a code sample or hint on how to get PRPT with charts to embed in HTML.

Thanks.

Marko Švaljek said...

YourSuperPrinter is just an example Class. I guess it'll have a lot of errors if you just copy paste it to the IDE. But all the functioning parts are there (follow the comments)

I'm not able to post the original class here but you can send me what you have to my e-mail msvaljek@gmail.com and I can give you directions from there.

Pehntaho documentation has a very limited online presence, that's why I created this post entry, I hope it helped you in some way!

Unknown said...

Your article was very helpful. I think the most current version of Pentaho Reports has changed its api where some of the functions in HtmlPrinter has been moved to the HtmlContentGenerator.

I subclassed the DefaultHtmlContentGenerator and overwrote the writeImage() method.

Then I subclassed the AllItemsHtmlPrinter and overwrote the getContentGenerator() method to return the newly created DefaultHtmlContentGenerator.

It looks like this implementation works as you describe in your article with version 5.3.0.0-213 of Pentaho Report Designer.

here is the code that I used (minus the imports).


public class ReportsHtmlContentGenerator extends DefaultHtmlContentGenerator {
public ReportsHtmlContentGenerator(org.pentaho.reporting.libraries.resourceloader.ResourceManager resourceManager) {
super( resourceManager );

}
@Override
public String writeImage(ImageContainer image, String encoderType, float quality, boolean alpha) throws org.pentaho.reporting.libraries.repository.ContentIOException, IOException {
if (image instanceof DefaultImageReference) {
DefaultImageReference dir = (DefaultImageReference) image;

if (dir.getImage() != null && encoderType != null) {
BufferedImage img = toBufferedImage(dir.getImage());

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ImageIO.write(img,
encoderType.substring(encoderType.indexOf("/") + 1),
baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();

String imageData = new String( Base64.encode(imageInByte) );

return "data:" + encoderType + ";base64," + imageData;
}
else {
return dir.getSourceURLString();
}
}
return super.writeImage(image, encoderType, quality, alpha);
}
private static BufferedImage toBufferedImage(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}

BufferedImage bimage = new BufferedImage(
img.getWidth(null), img.getHeight(null),
BufferedImage.TYPE_INT_ARGB);

Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();

return bimage;
}
}


public class ReportsHtmlPrinter extends AllItemsHtmlPrinter {
private ReportsHtmlContentGenerator contentGenerator;
public ReportsHtmlPrinter(ResourceManager resourceManager) {
super( resourceManager );
contentGenerator = new ReportsHtmlContentGenerator(resourceManager );
}

@Override
public void print(LogicalPageKey logicalPageKey, LogicalPageBox logicalPage, TableContentProducer contentProducer, OutputProcessorMetaData metaData, boolean incremental) throws ContentProcessingException {
super.print(logicalPageKey, logicalPage, contentProducer, metaData, incremental);

}
public ReportsHtmlContentGenerator getContentGenerator() {
return contentGenerator;
}

}

Unknown said...

Good Article. Thanks for the information. We also provide Pentaho online training.
check this site Tekslate for indepth Pentaho training.

Bruno Gama Catão said...

Thank you so much and thanks Al Corbin for the update.
You guys saved me many hours of work.