gr.abiss.calipso.util.PdfUtils.java Source code

Java tutorial

Introduction

Here is the source code for gr.abiss.calipso.util.PdfUtils.java

Source

/*
 * Copyright (c) 2007 - 2010 Abiss.gr <info@abiss.gr>  
 *
 *  This file is part of Calipso, a software platform by www.Abiss.gr.
 *
 *  Calipso is free software: you can redistribute it and/or modify 
 *  it under the terms of the GNU Affero General Public License as published by 
 *  the Free Software Foundation, either version 3 of the License, or 
 *  (at your option) any later version.
 * 
 *  Calipso is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *  GNU Affero General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License 
 *  along with Calipso. If not, see http://www.gnu.org/licenses/agpl.html
 */

package gr.abiss.calipso.util;

import gr.abiss.calipso.CalipsoService;
import gr.abiss.calipso.domain.Asset;
import gr.abiss.calipso.domain.AssetTypeCustomAttribute;
import gr.abiss.calipso.domain.Country;
import gr.abiss.calipso.domain.Item;
import gr.abiss.calipso.domain.Organization;
import gr.abiss.calipso.domain.User;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.wicket.Component;
import org.apache.wicket.Localizer;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.PrettyXmlSerializer;
import org.htmlcleaner.TagNode;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;
import org.xml.sax.InputSource;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;

/**
 * Excel Sheet generation helper
 */
public class PdfUtils {

    /**
     * Please make proper use of logging, see http://www.owasp.org/index.php/Category:Logging_and_Auditing_Vulnerability
     */
    private static final Logger logger = Logger.getLogger(PdfUtils.class);

    public static byte[] getPdf(CalipsoService calipso, Asset asset, Component callerComponent) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        String html = null;
        try {
            Localizer localizer = callerComponent.getLocalizer();
            String template = calipso.getPrintTemplateTextForAsset(asset.getId());// asset.getAssetType().getPrintingTemplate().getTemplateText();
            if (template != null) {
                // template exists, use it
                Reader templateReader = new StringReader(template);
                // create a Velocity context object and add the asset
                final VelocityContext context = new VelocityContext();
                context.put("rootAsset", asset);
                context.put("calipso", calipso);
                // create a writer for capturing the Velocity output
                StringWriter writer = new StringWriter();
                // execute the velocity script and capture the output in writer
                Velocity.evaluate(context, writer, asset.getInventoryCode(), templateReader);
                // get the output as a string
                html = writer.getBuffer().toString();
                // logger.debug("Velocity result: \n"+html);
            } else {
                StringBuffer htmlBuffer = getDefaultHeader();
                htmlBuffer
                        .append("<h1>").append(localizer
                                .getString(asset.getAssetType().getNameTranslationResourceKey(), callerComponent))
                        .append("</h1>");
                htmlBuffer.append("<table cellspacing='0'>");
                htmlBuffer.append("<tr><th>")
                        .append(localizer.getString("asset.form.inventoryCode", callerComponent))
                        .append("</th><td>").append(asset.getInventoryCode());
                htmlBuffer.append("</td></tr>");
                if (MapUtils.isNotEmpty(asset.getCustomAttributes())) {
                    Map<AssetTypeCustomAttribute, String> attrs = asset.getCustomAttributes();
                    for (Entry<AssetTypeCustomAttribute, String> entry : attrs.entrySet()) {
                        AssetTypeCustomAttribute customAttr = entry.getKey();
                        htmlBuffer
                                .append("<tr><th>").append(localizer
                                        .getString(customAttr.getNameTranslationResourceKey(), callerComponent))
                                .append("</th><td>");

                        if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_SELECT) || customAttr
                                .getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_OPTIONS_TREE)) {
                            htmlBuffer.append(XmlUtils.escapeHTML(localizer
                                    .getString(customAttr.getLookupValue().getNameTranslationResourceKey(), null)));
                        } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_USER)) {
                            User user = customAttr.getUserValue();
                            htmlBuffer.append(user != null ? XmlUtils.escapeHTML(user.getFullName()) : "");
                        } else if (customAttr.getFormType()
                                .equals(AssetTypeCustomAttribute.FORM_TYPE_ORGANIZATION)) {
                            Organization org = customAttr.getOrganizationValue();
                            htmlBuffer.append(org != null ? XmlUtils.escapeHTML(org.getName()) : "");
                        } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_ASSET)) {
                            Asset innerAsset = customAttr.getAssetValue();
                            htmlBuffer.append(
                                    innerAsset != null ? XmlUtils.escapeHTML(innerAsset.getInventoryCode()) : "");
                        } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_COUNTRY)) {
                            Country country = customAttr.getCountryValue();
                            htmlBuffer.append(country != null
                                    ? localizer.getString("country." + country.getId(), callerComponent)
                                    : "");
                        } else {
                            htmlBuffer.append(XmlUtils.escapeHTML(entry.getValue()));
                        }
                        htmlBuffer.append("</td></tr>");
                    }
                }
                htmlBuffer.append("</table>");

                htmlBuffer.append("</body></html>");
                html = htmlBuffer.toString();
            }
            // convert HTML string to PDF and store it in the buffer output stream 
        } catch (Exception e) {
            logger.error("Failed to creare PDF for asset, html: \n" + html, e);
        }
        writePdf(calipso, os, html);
        return os.toByteArray();
    }

    public static byte[] getPdf(CalipsoService calipso, Item item, String template, Component callerComponent) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        String html = null;
        try {
            Localizer localizer = callerComponent.getLocalizer();
            if (template != null) {
                // template exists, use it
                Reader templateReader = new StringReader(template);
                // create a Velocity context object and add the asset
                final VelocityContext context = new VelocityContext();
                context.put("item", item);
                context.put("calipso", calipso);
                // create a writer for capturing the Velocity output
                StringWriter writer = new StringWriter();
                // execute the velocity script and capture the output in writer
                Velocity.evaluate(context, writer, item.getRefId(), templateReader);
                // get the output as a string
                html = writer.getBuffer().toString();
            } else {
                // no template exists, just output manual HTML to feed xhtmlrenderer
                StringBuffer htmlBuffer = getDefaultHeader();
                htmlBuffer.append("<h1>").append(
                        localizer.getString(item.getSpace().getNameTranslationResourceKey(), callerComponent))
                        .append(": ").append(item.getRefId()).append("</h1>");
                //            htmlBuffer.append("<table cellspacing='0'>");
                //            htmlBuffer.append("<tr><th>")
                //               .append(localizer.getString("asset.form.inventoryCode", callerComponent))
                //               .append("</th><td>")
                //               .append(asset.getInventoryCode());
                //            htmlBuffer.append("</td></tr>");
                //            if(MapUtils.isNotEmpty(asset.getCustomAttributes())){
                //               Map<AssetTypeCustomAttribute,String> attrs = asset.getCustomAttributes();
                //               for(Entry<AssetTypeCustomAttribute, String> entry : attrs.entrySet()){
                //                  AssetTypeCustomAttribute customAttr = entry.getKey();
                //                  htmlBuffer.append("<tr><th>")
                //                     .append(localizer.getString(customAttr.getNameTranslationResourceKey(), callerComponent))
                //                     .append("</th><td>");
                //                  
                //                  if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_SELECT)
                //                        || customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_OPTIONS_TREE)) {
                //                     htmlBuffer.append(XmlUtils.escapeHTML(localizer.getString(customAttr.getLookupValue().getNameTranslationResourceKey(), null)));
                //                  }
                //                  else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_USER)) {
                //                     User user = customAttr.getUserValue();
                //                     htmlBuffer.append(user!=null?XmlUtils.escapeHTML(user.getFullName()):"");
                //                  } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_ORGANIZATION)) {
                //                     Organization org = customAttr.getOrganizationValue();
                //                     htmlBuffer.append(org!=null?XmlUtils.escapeHTML(org.getName()):"");
                //                  } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_ASSET)) {
                //                     Asset innerAsset = customAttr.getAssetValue();
                //                     htmlBuffer.append(innerAsset!=null?XmlUtils.escapeHTML(innerAsset.getInventoryCode()):"");
                //                  } else if (customAttr.getFormType().equals(AssetTypeCustomAttribute.FORM_TYPE_COUNTRY)) {
                //                     Country country = customAttr.getCountryValue();
                //                     htmlBuffer.append(country!=null?localizer.getString("country."+country.getId(), callerComponent):"");
                //                  } else {
                //                     htmlBuffer.append(XmlUtils.escapeHTML(entry.getValue()));
                //                  }
                //                  htmlBuffer.append("</td></tr>");
                //               }
                //            }
                //            htmlBuffer.append("</table>");
                htmlBuffer.append("</body></html>");

                html = htmlBuffer.toString();
            }
        } catch (Exception e) {
            logger.error("Failed to creare PDF for item, html: \n" + html, e);
        }
        // convert HTML string to PDF and store it in the buffer output stream
        writePdf(calipso, os, html);
        return os.toByteArray();
    }

    public static StringBuffer getDefaultHeader() {
        StringBuffer htmlBuffer = new StringBuffer("<?xml version='1.0' encoding='UTF-8'?>\n"
                + "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
                + "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>" + "<style type='text/css'>"
                + "#normalFooter, #firstPageFooter{font-size:12px;} " + "@page {" + "   padding-top:100px;"
                + "   background: url('watermark.png') no-repeat top center; "
                + "   @top-center { content: element(header) }" + "   @bottom-right {content: element(footer);}"
                + "}" + "@page :first {" + "   padding-top:10px;"
                + "   background: url('watermark.png') no-repeat center 30px; "
                + "   @top-center { content: element(header) }"
                + "   @bottom-right {content: element(firstPageFooter);}" + "}"
                + "#page:before {content: counter(page);}" + "#pagecount:before {content: counter(pages);} "
                + "#footer{position: running(footer);}" + "#firstPageFooter{position: running(firstPageFooter);}"
                + "#header {\n" + "   display: block; text-align: center;\n" + "   position: running(header);}\n"
                + "body { font-family: \"Arial Unicode MS\";margin:10px;padding:10px; }th{width:50%;background:#EEEEEE;}td, th{border:1px solid #EEEEEE;padding-left:4px;padding-right:4px;vertical-align:top;}table{border-collapse:collapse;}</style></head><body>"
                + "<div id='header'>Header</div>").append(
                        "<div id='footer' style=''><div class='footerContent'>Page <span id='page'/> of <span id='pagecount'/></div></div>")
                        .append("<div id='firstPageFooter' style=''><div class='footerContent'>Page <span id='page'/> of <span id='pagecount'/></div></div>");
        //      "<html><head><style>\n" +
        //        "div.footer {\n" +
        //        "display: block; text-align: center;\n" + 
        //        "position: running(footer);}\n" +
        //        "div.content {page-break-after: always;}" +
        //        "@page { }\n " +
        //        "@page { @bottom-center { content: element(footer) }}\n" +
        //        "</style></head>\n" +
        //        "<body><div class='header'>Header</div><div class='footer'>Footer</div><div class='content'>Page1</div><div>Page2</div></body></html>";

        return htmlBuffer;
    }

    //   public static void appendDefaultFooter(StringBuffer htmlBuffer) {
    //      
    //   }

    /**
     * @param fontDir
     * @param os
     * @param html
     * @throws DocumentException
     * @throws IOException
     */
    public static void writePdf(CalipsoService calipso, OutputStream os, String html) {
        writePdf(calipso.getFontsDirPath(), calipso.getResourcesDirPath(), os, html);
    }

    public static void writePdf(String fontDir, String resourcesBasePath, OutputStream os, String html) {
        try {
            // Create a buffer to hold the cleaned up HTML
            // Note: you can safely ignore both flush() and close(),
            // as they do nothing in ByteArrayOutputStream's implementation.
            // ByteArrayOutputStream out = new ByteArrayOutputStream();

            // Clean up the HTML to be well formed
            HtmlCleaner cleaner = new HtmlCleaner();
            CleanerProperties props = cleaner.getProperties();
            props.setAdvancedXmlEscape(true);
            props.setRecognizeUnicodeChars(true);
            props.setTranslateSpecialEntities(true);
            props.setUseCdataForScriptAndStyle(false);
            props.setOmitXmlDeclaration(false);
            props.setOmitDoctypeDeclaration(false);
            TagNode node = cleaner.clean(html);
            // write to the ByteArray buffer
            html = new PrettyXmlSerializer(props).getAsString(node);
            // logger.info("CLEANED HTML: " + html);
            // update the html string using the cleaned-up version
            // html = new String(out.toByteArray());

            ITextRenderer renderer = new ITextRenderer();
            renderer.getFontResolver().addFont(fontDir + File.separator + "ARIALUNI.TTF", BaseFont.IDENTITY_H,
                    BaseFont.EMBEDDED);
            if (StringUtils.isNotBlank(resourcesBasePath)) {
                try {
                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

                    factory.setValidating(false);
                    factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

                    DocumentBuilder builder = factory.newDocumentBuilder();
                    InputSource is = new InputSource(new StringReader(html));
                    Document doc = builder.parse(is);
                    String rsPath = new File(resourcesBasePath + File.separator).toURI().toURL().toString();
                    renderer.setDocument(doc, rsPath);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } else {
                renderer.setDocumentFromString(html);
            }
            renderer.layout();
            renderer.createPDF(os);
        } catch (Exception e) {
            logger.error("Failed to creare PDF for item, html: \n" + html, e);
        }
    }

    /**
     * @param fontDir
     * @param os
     * @param html
     * @throws DocumentException
     * @throws IOException
     */
    @Deprecated
    public static void writePdf(String fontDir, OutputStream os, String html)
            throws DocumentException, IOException {
        writePdf(fontDir, null, os, html);
    }

}