Please disable your adblock and script blockers to view this page

Search this blog

Wednesday, 1 February 2017

Export ViewObject data to PDF file using Apache PDFBox

Hello All
Hope you all are doing well :)

This post is about exporting view object data in a pdf file directly from af:table , export to excel is built in feature of ADF but exporting data in PDF requires little bit of extra effort
So here for this requirement I am using Apache PDFBox library , previously I have posted about using this API to create PDF file from text data
I know many of you will not visit that link ;) So a quick overview



What is Apache PDFBox


The Apache PDFBox library is an open source Java tool for working with PDF documents. This project allows creation of new PDF documents, manipulation of existing documents and the ability to extract content from documents. Apache PDFBox also includes several command line utilities.

Let's implement this

  • Create a Fusion Web Application and prepare model using Departments table of HR Schema


  • Add PDFBox jar to view controller project


  • Drop Departments view object as table on page and add two buttons to Export All Rows and Export Selected Row


  • Now see the managed bean code that exports viewObject data to PDF file , Idea is to add viewObject data in a multi dimensional array and then iterate over array to draw a table in pdf Go through the comments to understand code part

Packages and Helper method-


import java.io.IOException;

import javax.faces.event.ActionEvent;

import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCIteratorBinding;

import oracle.binding.BindingContainer;

import oracle.jbo.Row;
import oracle.jbo.RowSetIterator;
import oracle.jbo.ViewObject;

import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

 /**
     * Generic Method to call operation binding**/
    public BindingContainer getBindingsCont() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }

Method to Export All Rows of ViewObject to PDF-


    /**Method to export all rows of viewObject to PDF
     * @param actionEvent
     * @throws IOException
     */
    public void exportAllRowsToPdfAction(ActionEvent actionEvent) throws IOException {
        //Create new PDF Document
        PDDocument document = new PDDocument();
        PDPage page = new PDPage();
        document.addPage(page);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);

        //Get the iterator of af:table on page
        DCIteratorBinding iter = (DCIteratorBinding) getBindingsCont().get("DepartmentsVO1Iterator");
        //No of total rows+ 1 for array sizing
        int totRows = ((int) iter.getEstimatedRowCount()) + 1;
        //Here 4 is the number of columns
        String[][] content = new String[totRows][4];

        int column = 4;
        //Set header text in first row of table in PDF
        content[0][0] = "Department Id";
        content[0][1] = "Department Name";
        content[0][2] = "Manager Id";
        content[0][3] = "Location Id";

        //Get viewObject from iterator and Iterate over it to add all data in array
        ViewObject vo = iter.getViewObject();
        RowSetIterator rsi = vo.createRowSetIterator(null);
        int i = 1;
        while (rsi.hasNext()) {
            Row nextRow = rsi.next();

            for (int j = 0; j < column; j++) {
                System.out.println(i + "" + j);
                if (j == 0 && nextRow.getAttribute("DepartmentId") != null) {
                    content[i][j] = nextRow.getAttribute("DepartmentId").toString();
                }
                if (j == 1 && nextRow.getAttribute("DepartmentName") != null) {
                    content[i][j] = nextRow.getAttribute("DepartmentName").toString();
                }
                if (j == 2 && nextRow.getAttribute("ManagerId") != null) {
                    content[i][j] = nextRow.getAttribute("ManagerId").toString();
                }
                if (j == 3 && nextRow.getAttribute("LocationId") != null) {
                    content[i][j] = nextRow.getAttribute("LocationId").toString();
                }
            }
            i++;
        }
        rsi.closeRowSetIterator();
        //Write data to PDF
        writeToPdf(contentStream, content);

        contentStream.close();
        try {
            //Save generated pdf document in a drive
            document.save("D:\\Departments.pdf");
        } catch (COSVisitorException e) {
        }
    }

Method to Export Selected Row of ViewObject to PDF-


    /**Method to export selected row to PDF
     * @param actionEvent
     * @throws IOException
     */
    public void exportCurRowToPdfAction(ActionEvent actionEvent) throws IOException {
        //Create new PDF Document
        PDDocument document = new PDDocument();
        PDPage page = new PDPage();
        document.addPage(page);
        PDPageContentStream contentStream = new PDPageContentStream(document, page);

        //Get the iterator of af:table on page
        DCIteratorBinding iter = (DCIteratorBinding) getBindingsCont().get("DepartmentsVO1Iterator");
        //Define the array for two rows only
        String[][] data = new String[2][4];

        //Set header text in first row of table in PDF
        data[0][0] = "Department Id";
        data[0][1] = "Department Name";
        data[0][2] = "Manager Id";
        data[0][3] = "Location Id";

        //Get current row of Iterator and insert data in array
        Row row = iter.getCurrentRow();

        if (row.getAttribute("DepartmentId") != null) {
            data[1][0] = row.getAttribute("DepartmentId").toString();
        }
        if (row.getAttribute("DepartmentName") != null) {
            data[1][1] = row.getAttribute("DepartmentName").toString();
        }
        if (row.getAttribute("ManagerId") != null) {
            data[1][2] = row.getAttribute("ManagerId").toString();
        }
        if (row.getAttribute("LocationId") != null) {
            data[1][3] = row.getAttribute("LocationId").toString();
        }
        //Write data to PDF
        writeToPdf(contentStream, data);

        contentStream.close();
        try {
            //Save generated pdf document in a drive
            document.save("D:\\Departments.pdf");
        } catch (COSVisitorException e) {
        }
    }

Method to draw table in PDF -


    /**Method to draw table on pdf using array of data
     * @param page
     * @param contentStream
     * @param y
     * @param margin
     * @param content
     * @throws IOException
     */
    public static void writeToPdf(PDPageContentStream contentStream, String[][] data) throws IOException {
        final int rows = data.length;
        final int cols = data[0].length;

        //Height for each row
        final float rowHeight = 20f;
        //Width of table drawn
        final float tableWidth = 550;

        //Total table height
        final float tableHeight = rowHeight * rows;
        //Width of each column
        final float colWidth = tableWidth / (float) cols;
        final float cellMargin = 5f;
        //Margin from left
        float margin = 20;
        //Margin from top (Increase value to decrease margin)
        float y = 750;
        //draw the rows
        float anoy = y;

        for (int i = 0; i <= rows; i++) {
            contentStream.drawLine(margin, anoy, margin + tableWidth, anoy);
            anoy -= rowHeight;
        }

        //Draw the columns
        float anox = margin;
        for (int i = 0; i <= cols; i++) {
            contentStream.drawLine(anox, y, anox, y - tableHeight);
            anox += colWidth;
        }

        //Setting for font and size
        contentStream.setFont(PDType1Font.COURIER_BOLD, 10);

        float textx = margin + cellMargin;
        float texty = y - 15;
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != null) {
                    String text = data[i][j];

                    contentStream.beginText();
                    contentStream.moveTextPositionByAmount(textx, texty);
                    contentStream.drawString(text);
                    contentStream.endText();
                    textx += colWidth;
                }
            }
            texty -= rowHeight;
            textx = margin + cellMargin;
        }
    }

All Done :) Now run and check application



Sample ADF Application (Jdeveloper 12.1.3)- Download
Cheers :) Happy Learning

3 comments :

  1. This is terribly inefficient. It will take a very long time to create detailed pdf which includes multiple view objects with and without master-child relationships. Instead of this, I strongly recommend using Oracle Bi Desktop Publisher libraries instead of pdfbox, creating java class to convert view objects to xml, and pass that xml to the Publisher libraries. Then all you need to do is draw .rtf template in word and pass it as input to Publisher as well. I can provide example if you want.

    ReplyDelete
    Replies
    1. This is for a single viewObject , If you need to create detailed report then you can use any report tool like jasper and call that in application using integration libraries or the way you suggested above :)

      Delete
  2. Thanks a lot....Without your posting definitely face problems in our development.

    ReplyDelete