de.xirp.report.ReportGenerator.java Source code

Java tutorial

Introduction

Here is the source code for de.xirp.report.ReportGenerator.java

Source

/** 
 * ============================================================================
 * Xirp 2: eXtendable interface for robotic purposes.
 * ============================================================================
 * 
 * Copyright (C) 2005-2007, by Authors and Contributors listed in CREDITS.txt
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at:
 *
 *             http://www.opensource.org/licenses/cpl1.0.php
 *
 * ----------------------------
 * ReportGenerator.java
 * ----------------------------
 *
 * Original Author:  Matthias Gernand [matthias.gernand AT gmx.de]
 * Contributor(s):   
 *
 * Changes
 * -------
 * 17.04.2006:      Created by Matthias Gernand.
 */
package de.xirp.report;

import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;

import org.apache.log4j.Logger;

import com.lowagie.text.*;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

import de.xirp.db.ReportDatabaseUtil;
import de.xirp.report.data.ContentPart;
import de.xirp.report.data.ContentPartImage;
import de.xirp.report.data.ContentPartList;
import de.xirp.report.data.ContentPartTable;
import de.xirp.report.data.ContentPartTableRow;
import de.xirp.report.data.ContentPartText;
import de.xirp.report.data.ContentPartTextParagraph;
import de.xirp.report.data.Header;
import de.xirp.report.data.IContentPartItem;
import de.xirp.report.data.ContentPartList.ListType;
import de.xirp.ui.util.ApplicationManager;
import de.xirp.util.Constants;
import de.xirp.util.I18n;
import de.xirp.util.Util;

/**
 * The class generates a PDF from a
 * {@link de.xirp.report.Report} object. Therefore the
 * generator offers one publicly available static method. This method
 * gets a {@link de.xirp.report.Report} object as
 * parameter. The PDF is generated from the object and is saved to the
 * database and as file in the <code>reports</code> directory. The
 * file name is generated automatically from the available
 * informations.
 * 
 * @author Matthias Gernand
 * @see de.xirp.report.Report
 */
public final class ReportGenerator {

    /**
     * The logger for this class.
     */
    private static final Logger logClass = Logger.getLogger(ReportGenerator.class);
    /**
     * The {@link com.lowagie.text.Document document} data structure
     * for generating a PDF in memory.
     * 
     * @see com.lowagie.text.Document
     */
    private static Document document = null;
    /**
     * The {@link de.xirp.report.Report report} data
     * structure which contains the report data.
     * 
     * @see de.xirp.report.Report
     */
    private static Report report = null;
    /**
     * A {@link com.lowagie.text.Font font} for the header.
     * 
     * @see com.lowagie.text.Font
     */
    private static final Font HEADER = new Font(Font.HELVETICA, 24, Font.BOLD);
    /**
     * A {@link com.lowagie.text.Font font} for the images.
     * 
     * @see com.lowagie.text.Font
     */
    private static final Font IMAGE = new Font(Font.HELVETICA, 8, Font.ITALIC);
    /**
     * A {@link com.lowagie.text.Font font} for the text.
     * 
     * @see com.lowagie.text.Font
     */
    private static final Font TEXT = new Font(Font.HELVETICA, 12, Font.NORMAL);
    /**
     * A {@link com.lowagie.text.Font font} for the paragraph headers.
     * 
     * @see com.lowagie.text.Font
     */
    private static final Font PARA_HEADER = new Font(Font.HELVETICA, 14, Font.BOLD);
    /**
     * The counter for the images contained in the report.
     */
    private static int imageCounter = 0;
    /**
     * The counter for the tables contained in the report.
     */
    private static int tableCounter = 0;
    // private static int videoCounter = 0;
    /**
     * A {@link com.lowagie.text.Paragraph paragraph} in a PDF.
     * 
     * @see com.lowagie.text.Paragraph
     */
    private static Paragraph para;
    /**
     * A {@link com.lowagie.text.pdf.PdfWriter writer} which actually
     * writes the PDF.
     * 
     * @see com.lowagie.text.pdf.PdfWriter
     */
    private static PdfWriter writer;
    /**
     * The first content
     * {@link de.xirp.report.data.IContentPartItem item}.
     * 
     * @see de.xirp.report.data.IContentPartItem
     */
    private static IContentPartItem first;
    /**
     * The report {@link java.io.File}.
     */
    private static File reportFile;

    /**
     * Default constructor declared private to avoid user errors and
     * misuse.
     */
    private ReportGenerator() {

    }

    /**
     * Generates the report as PDF and saves it to the
     * <code>reports</code> directory. After that the report PDF
     * data is stored it the database. Therefore the
     * {@link de.xirp.report.ReportDescriptor} object is
     * created. This object can be persisted in a database using
     * Hibernate.
     * 
     * @param report
     *            The report to generate the PDF for.
     * @return The path to the generated PDF document.
     * @throws ReportException
     *             when one of the required data objects is
     *             <code>null</code>.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong generating the PDF.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @see de.xirp.report.ReportDescriptor
     */
    public static String generateReport(Report report)
            throws ReportException, MalformedURLException, DocumentException, IOException {
        ReportGenerator.report = report;
        ReportDescriptor data = new ReportDescriptor();
        data.setFileName(generate());
        data.setCreationTime(report.getHeader().getDate().getTime());
        data.setRobotName(report.getHeader().getRobot().getName());
        data.setReportName(report.getName());
        try {
            ReportDatabaseUtil.storePDF(data);
        } catch (Exception e) {
            logClass.error("Error storing report: " + e.getMessage() + Constants.LINE_SEPARATOR, e);
        }
        return data.getFileName();
    }

    /**
     * Generates the report and returns the path to the PDF file. This
     * file is generated in the <code>reports</code> directory.
     * 
     * @return The path to the generated PDF document.
     * @throws ReportException
     *             when one of the required data objects is
     *             <code>null</code>.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong generating the PDF.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     */
    private static String generate() throws ReportException, MalformedURLException, DocumentException, IOException {
        if (report.getName() == null) {
            throw new ReportException(I18n.getString("ReportGenerator.exception.reportNameIsNull")); //$NON-NLS-1$
        } else if (report.getName().equals("")) { //$NON-NLS-1$
            throw new ReportException(I18n.getString("ReportGenerator.exception.reportNameIsEmpty")); //$NON-NLS-1$
        } else if (report.getHeader() == null) {
            throw new ReportException(I18n.getString("ReportGenerator.exception.reportHeaderIsNUll")); //$NON-NLS-1$
        } else if (report.getContent() == null) {
            throw new ReportException(I18n.getString("ReportGenerator.exception.reportContentIsNull")); //$NON-NLS-1$
        } else {
            return generatePDF();
        }
    }

    /**
     * Generates the PDF from the
     * {@link de.xirp.report.Report} and writes the PDF
     * to a file. <br>
     * <br>
     * At first the title and header pages are created. After that the
     * content pages are created.
     * 
     * @return The file name of the PDF.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong generating the PDF.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @see de.xirp.report.Report
     */
    private static String generatePDF() throws DocumentException, MalformedURLException, IOException {
        String filename = report.getName().replaceAll(" ", "-") + "_report_" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                + report.getHeader().getRobot().getName() + "_" //$NON-NLS-1$
                + Util.getTimeAsString(report.getHeader().getDate()) + ".pdf"; //$NON-NLS-1$

        reportFile = new File(Constants.REPORT_DIR + File.separator + filename);

        // creation of a document-object
        document = new Document(PageSize.A4);

        // we create a writer that listens to the document
        // and directs a PDF-stream to a file
        writer = PdfWriter.getInstance(document, new FileOutputStream(reportFile.getPath()));
        writer.setPdfVersion(PdfWriter.VERSION_1_7);
        writer.setStrictImageSequence(true);

        // open the document
        document.open();

        // add the title page
        addReportTitle();
        addReportContent();
        // close the document
        document.close();

        return filename;
    }

    /**
     * Adds the report title page to the PDF
     * {@link com.lowagie.text.Document}.
     * 
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see com.lowagie.text.Document
     */
    private static void addReportTitle() throws DocumentException {
        String heading = null;
        heading = I18n.getString("ReportGenerator.text.reportTitle", report.getName(), //$NON-NLS-1$
                Constants.LINE_SEPARATOR, ApplicationManager.getCurrentRobot().getName());
        addTitle(heading);
        addHeader();
    }

    /**
     * Adds the title page with the given header string to the PDF
     * {@link com.lowagie.text.Document}.
     * 
     * @param heading
     *            The header text.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see com.lowagie.text.Document
     */
    private static void addTitle(String heading) throws DocumentException {

        para = getParagraph(heading, HEADER, Element.ALIGN_CENTER);
        document.add(para);
        addSkip(3);
        para = getParagraph(Constants.NON_UNICODE_APP_NAME, IMAGE, Image.ALIGN_CENTER);
        document.add(para);

        addSkip();

        para = getParagraph(I18n.getString("ReportGenerator.report.header.website"), TEXT, //$NON-NLS-1$
                Element.ALIGN_CENTER);
        document.add(para);

        para = getParagraph(Constants.LINE_SEPARATOR, TEXT, Element.ALIGN_CENTER);
        TEXT.setColor(new Color(0, 0, 255));
        Anchor anchor = new Anchor(I18n.getString("ReportGenerator.report.websiteLink"), TEXT); //$NON-NLS-1$
        anchor.setReference(I18n.getString("ReportGenerator.report.websiteLink")); //$NON-NLS-1$
        anchor.setName("homepage"); //$NON-NLS-1$
        para.add(anchor);
        document.add(para);
        document.newPage();
        TEXT.setColor(new Color(0, 0, 0));

        document.newPage();
    }

    /**
     * Adds the header page to the PDF
     * {@link com.lowagie.text.Document}.
     * 
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see com.lowagie.text.Document
     */
    private static void addHeader() throws DocumentException {
        Header header = report.getHeader();

        para = getParagraph(header.getTitle(), HEADER, Element.ALIGN_CENTER);
        document.add(para);
        addSkip(4);
        List list = getList(ListType.BULLET);
        list.add(new ListItem(I18n.getString("ReportGenerator.report.header.created.date") //$NON-NLS-1$
                + " " + Util.getTimeAsString(header.getDate(), "dd.MM.yyyy"))); //$NON-NLS-1$ //$NON-NLS-2$
        list.add(new ListItem(I18n.getString("ReportGenerator.report.header.created.time") //$NON-NLS-1$
                + " " //$NON-NLS-1$
                + Util.getTimeAsString(header.getDate(), "HH:mm") //$NON-NLS-1$
                + I18n.getString("ReportGenerator.report.oClock"))); //$NON-NLS-1$
        list.add(new ListItem(I18n.getString("ReportGenerator.report.header.created.plugin") //$NON-NLS-1$
                + " " + header.getPlugin().getName())); //$NON-NLS-1$
        list.add(new ListItem(I18n.getString("ReportGenerator.report.header.created.robot") //$NON-NLS-1$
                + " " + header.getRobot().getName())); //$NON-NLS-1$
        document.add(list);
    }

    /**
     * Adds the reports
     * {@link de.xirp.report.data.ContentPart content}
     * pages.
     * 
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @see de.xirp.report.data.ContentPart
     */
    private static void addReportContent() throws MalformedURLException, IOException, DocumentException {
        addParts();
    }

    /**
     * Adds the parts to the PDF {@link com.lowagie.text.Document}.
     * 
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see de.xirp.report.data.ContentPart
     * @see com.lowagie.text.Document
     */
    private static void addParts() throws MalformedURLException, IOException, DocumentException {
        for (ContentPart part : report.getContent().getParts()) {
            first = part.getItems().get(0);
            addPart(part, first);
        }
    }

    /**
     * Adds a
     * {@link de.xirp.report.data.ContentPart part} to
     * the PDF {@link com.lowagie.text.Document}.
     * 
     * @param part
     *            The content part to add.
     * @param first
     *            The first added item.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see de.xirp.report.data.ContentPart
     * @see de.xirp.report.data.IContentPartItem
     * @see com.lowagie.text.Document
     */
    private static void addPart(ContentPart part, IContentPartItem first)
            throws MalformedURLException, IOException, DocumentException {

        if (first instanceof ContentPartTable) {
            document.setPageSize(PageSize.A4.rotate());
        }
        document.newPage();

        for (IContentPartItem item : part.getItems()) {
            if (item instanceof ContentPartImage) {
                logClass.debug("IMAGE part created in report." + Constants.LINE_SEPARATOR); //$NON-NLS-1$
                addImage((ContentPartImage) item);
                addSkip();
            }
            if (item instanceof ContentPartText) {
                logClass.debug("TEXT part created in report." + Constants.LINE_SEPARATOR); //$NON-NLS-1$
                addText((ContentPartText) item);
                addSkip();
            }
            if (item instanceof ContentPartTable) {
                logClass.debug("TABLE part created in report." + Constants.LINE_SEPARATOR); //$NON-NLS-1$
                if (!first.equals(item)) {
                    document.setPageSize(PageSize.A4.rotate());
                    document.newPage();
                }
                addTable((ContentPartTable) item);
                document.setPageSize(PageSize.A4);
                document.newPage();
            }
            if (item instanceof ContentPartList) {
                logClass.debug("LIST part created in report." + Constants.LINE_SEPARATOR); //$NON-NLS-1$
                addList((ContentPartList) item);
                addSkip();
            }
            // if (item instanceof ContentPartVideo) {
            // logClass.debug("VIDEO part created in
            // report."+Constants.LINE_SEPARATOR);
            // //$NON-NLS-1$
            // addVideo((ContentPartVideo) item);
            // addSkip( );
            // }
        }
        logClass.debug("Part finished." + Constants.LINE_SEPARATOR); //$NON-NLS-1$
    }

    /**
     * Adds a
     * {@link de.xirp.report.data.ContentPartText text}
     * item to the PDF {@link com.lowagie.text.Document}.
     * 
     * @param item
     *            The item to add.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see de.xirp.report.data.ContentPartText
     * @see com.lowagie.text.Document
     */
    private static void addText(ContentPartText item) throws DocumentException {
        for (ContentPartTextParagraph cptp : item.getParagraphs()) {
            if (!cptp.getHeader().equals("")) { //$NON-NLS-1$
                para = getParagraph(cptp.getHeader(), PARA_HEADER, Element.ALIGN_LEFT);
                document.add(para);
            }
            para = getParagraph(cptp.getText(), TEXT, Element.ALIGN_JUSTIFIED);
            document.add(para);
            addSkip();
        }
    }

    /**
     * Adds a
     * {@link de.xirp.report.data.ContentPartList list}
     * item to the PDF {@link com.lowagie.text.Document}.
     * 
     * @param contentPartlist
     *            The list item to add.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see de.xirp.report.data.ContentPartList
     * @see com.lowagie.text.Document
     */
    private static void addList(ContentPartList contentPartlist) throws DocumentException {
        List list = getList(contentPartlist.getType());

        for (String item : contentPartlist.getEntrys()) {
            list.add(new ListItem(item));
        }
        document.add(list);
    }

    /**
     * Adds a
     * {@link de.xirp.report.data.ContentPartImage image}
     * item to the PDF {@link com.lowagie.text.Document}.
     * 
     * @param item
     *            The image item to add.
     * @throws IOException
     *             if something went wrong saving the PDF.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @throws MalformedURLException
     *             if something went wrong saving the PDF.
     * @see de.xirp.report.data.ContentPartImage
     * @see com.lowagie.text.Document
     */
    private static void addImage(ContentPartImage item)
            throws MalformedURLException, IOException, DocumentException {

        imageCounter++;

        String path = ""; //$NON-NLS-1$
        File file = new File(item.getPath());
        if (file.exists()) {
            path = item.getPath();
        }

        Image image = Image.getInstance(path);
        image.setAlignment(Image.MIDDLE);
        int maxWidth = 500;
        float plain = image.plainWidth();
        if (plain > maxWidth) {
            float percentage = maxWidth / plain;
            image.scalePercent(percentage * 100);
        }
        document.add(image);
        document.add(getParagraph(I18n.getString("ReportGenerator.report.document.image") //$NON-NLS-1$
                + " " + imageCounter + ": " + item.getShortDescription(), //$NON-NLS-1$ //$NON-NLS-2$
                IMAGE, Element.ALIGN_CENTER));

    }

    // private static void addVideo(ContentPartVideo video)
    // throws DocumentException {
    // // Testweise mal ein video eingefgt.
    // document.add(new
    // Paragraph("Test"+Constants.LINE_SEPARATOR+Constants.LINE_SEPARATOR+Constants.LINE_SEPARATOR));
    // //$NON-NLS-1$
    // PdfContentByte cb = writer.getDirectContent( );
    // Annotation a = new Annotation(100f, 700f, 200f, 800f,
    // "./cards.mpg", //$NON-NLS-1$
    // "video/mpeg", true); //$NON-NLS-1$
    // document.add(a);
    // // draw rectangles to show where the annotations were added
    // cb.rectangle(100, 700, 100, 100);
    // cb.stroke( );
    // }

    /**
     * Adds a
     * {@link de.xirp.report.data.ContentPartTable table}
     * item to the PDF {@link com.lowagie.text.Document}.
     * 
     * @param reportTable
     *            The table to add.
     * @throws DocumentException
     *             if something went wrong adding the page.
     * @see de.xirp.report.data.ContentPartTable
     * @see com.lowagie.text.Document
     */
    private static void addTable(ContentPartTable reportTable) throws DocumentException {

        tableCounter++;
        PdfPTable table = new PdfPTable(reportTable.getColumnCount());

        for (String cellHeader : reportTable.getHeader().getColumnHeaders()) {
            table.addCell(cellHeader);
        }
        logClass.debug("Table row count: " + reportTable.getRows().size() //$NON-NLS-1$
                + Constants.LINE_SEPARATOR);
        for (ContentPartTableRow row : reportTable.getRows()) {
            for (int i = 0; i < reportTable.getColumnCount(); i++) {
                table.addCell(row.getRowEntrys().get(i));
            }
        }

        // cell = new PdfPCell(new Paragraph("cell test1"));
        // cell.setBorderColor(new Color(255, 0, 0));
        // table.addCell(cell);
        // cell = new PdfPCell(new Paragraph("cell test2"));
        // cell.setColspan(2);
        // cell.setBackgroundColor(new Color(0xC0, 0xC0, 0xC0));
        // table.addCell(cell);

        document.add(table);
        document.add(getParagraph(I18n.getString("ReportGenerator.report.document.table") + " " //$NON-NLS-1$ //$NON-NLS-2$
                + tableCounter + ": " //$NON-NLS-1$
                + reportTable.getShortDescription(), IMAGE, Element.ALIGN_CENTER));
    }

    /**
     * Returns a default formatted
     * {@link com.lowagie.text.Paragraph paragraph}.
     * 
     * @param text
     *            The text for the paragraph.
     * @param font
     *            The font to use.
     * @param align
     *            The text alignment.
     * @return The default formatted paragraph.
     * @see com.lowagie.text.Paragraph
     */
    private static Paragraph getParagraph(String text, Font font, int align) {
        Paragraph para = new Paragraph(text, font);
        para.setFirstLineIndent(0);
        para.setAlignment(align);
        return para;
    }

    /**
     * Adds a one-line skip to the PDF
     * {@link com.lowagie.text.Document}.
     * 
     * @throws DocumentException
     *             if something went wrong adding the skip.
     * @see com.lowagie.text.Document
     */
    private static void addSkip() throws DocumentException {
        addSkip(1);
    }

    /**
     * Adds a skip for the given count of lines to the PDF
     * {@link com.lowagie.text.Document}.
     * 
     * @param count
     *            The count of lines to skip.
     * @throws DocumentException
     *             if something went wrong adding the skip.
     * @see com.lowagie.text.Document
     */
    private static void addSkip(int count) throws DocumentException {
        Paragraph para;
        if (count == 1) {
            para = new Paragraph(Constants.LINE_SEPARATOR + Constants.LINE_SEPARATOR);
            document.add(para);
        } else {
            for (int i = 0; i < count; i++) {
                para = new Paragraph(Constants.LINE_SEPARATOR + Constants.LINE_SEPARATOR);
                document.add(para);
            }
        }
    }

    /**
     * Returns a default formatted list for the given list type.
     * 
     * @param type
     *            The list type.
     * @return A default formatted list.
     */
    private static List getList(ListType type) {
        switch (type) {
        case BULLET:
            List list = new List(false, 20);
            list.setListSymbol(new Chunk("\u2022", FontFactory.getFont( //$NON-NLS-1$
                    FontFactory.HELVETICA, 12, Font.BOLD)));
            return list;
        case DASH:
            return new List(false, 20);
        case NUMBER:
            return new List(true, 20);
        }
        return null;
    }
}