net.sf.jasperreports.engine.export.JsonExporter.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jasperreports.engine.export.JsonExporter.java

Source

/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
 */
package net.sf.jasperreports.engine.export;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRGenericPrintElement;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintHyperlink;
import net.sf.jasperreports.engine.JRPrintPage;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.PrintBookmark;
import net.sf.jasperreports.engine.PrintPart;
import net.sf.jasperreports.engine.PrintParts;
import net.sf.jasperreports.engine.ReportContext;
import net.sf.jasperreports.engine.util.HyperlinkData;
import net.sf.jasperreports.export.ExportInterruptedException;
import net.sf.jasperreports.export.ExporterInputItem;
import net.sf.jasperreports.export.HtmlReportConfiguration;
import net.sf.jasperreports.export.JsonExporterConfiguration;
import net.sf.jasperreports.export.JsonExporterOutput;
import net.sf.jasperreports.export.JsonReportConfiguration;
import net.sf.jasperreports.web.util.JacksonUtil;

/**
 * @author Lucian Chirita (lucianc@users.sourceforge.net)
 */
public class JsonExporter extends
        JRAbstractExporter<JsonReportConfiguration, JsonExporterConfiguration, JsonExporterOutput, JsonExporterContext> {
    private static final Log log = LogFactory.getLog(JsonExporter.class);

    public static final String REPORT_CONTEXT_PARAMETER_WEB_FONTS = "net.sf.jasperreports.html.webfonts";

    public static final String JSON_EXPORTER_KEY = JRPropertiesUtil.PROPERTY_PREFIX + "json";

    protected static final String JSON_EXPORTER_PROPERTIES_PREFIX = JRPropertiesUtil.PROPERTY_PREFIX
            + "export.json.";

    protected Writer writer;
    protected int reportIndex;
    protected int pageIndex;
    private boolean gotFirstJsonFragment;
    private JacksonUtil jacksonUtil;
    private List<HyperlinkData> hyperlinksData;

    public JsonExporter() {
        this(DefaultJasperReportsContext.getInstance());
    }

    public JsonExporter(JasperReportsContext jasperReportsContext) {
        super(jasperReportsContext);

        exporterContext = new ExporterContext();
        jacksonUtil = JacksonUtil.getInstance(jasperReportsContext);
        hyperlinksData = new ArrayList<HyperlinkData>();
    }

    @Override
    protected Class<JsonExporterConfiguration> getConfigurationInterface() {
        return JsonExporterConfiguration.class;
    }

    @Override
    protected Class<JsonReportConfiguration> getItemConfigurationInterface() {
        return JsonReportConfiguration.class;
    }

    @Override
    @SuppressWarnings("deprecation")
    protected void ensureOutput() {
        if (exporterOutput == null) {
            exporterOutput = new net.sf.jasperreports.export.parameters.ParametersJsonExporterOutput(
                    getJasperReportsContext(), getParameters(), getCurrentJasperPrint());
        }
    }

    @Override
    public String getExporterKey() {
        return JSON_EXPORTER_KEY;
    }

    @Override
    public String getExporterPropertiesPrefix() {
        return JSON_EXPORTER_PROPERTIES_PREFIX;
    }

    @Override
    public void exportReport() throws JRException {
        /*   */
        ensureJasperReportsContext();
        ensureInput();

        //FIXMENOW check all exporter properties that are supposed to work at report level

        initExport();

        ensureOutput();

        writer = getExporterOutput().getWriter();

        try {
            exportReportToWriter();
        } catch (IOException e) {
            throw new JRException(EXCEPTION_MESSAGE_KEY_OUTPUT_WRITER_ERROR, new Object[] { jasperPrint.getName() },
                    e);
        } finally {
            getExporterOutput().close();
            resetExportContext();//FIXMEEXPORT check if using same finally is correct; everywhere
        }
    }

    @Override
    protected void initExport() {
        super.initExport();
    }

    @Override
    protected void initReport() {
        super.initReport();
    }

    protected void exportReportToWriter() throws JRException, IOException {
        writer.write("{\n");

        List<ExporterInputItem> items = exporterInput.getItems();

        for (reportIndex = 0; reportIndex < items.size(); reportIndex++) {
            ExporterInputItem item = items.get(reportIndex);

            setCurrentExporterInputItem(item);

            List<JRPrintPage> pages = jasperPrint.getPages();
            if (pages != null && pages.size() > 0) {
                PageRange pageRange = getPageRange();
                int startPageIndex = (pageRange == null || pageRange.getStartPageIndex() == null) ? 0
                        : pageRange.getStartPageIndex();
                int endPageIndex = (pageRange == null || pageRange.getEndPageIndex() == null) ? (pages.size() - 1)
                        : pageRange.getEndPageIndex();

                JRPrintPage page = null;
                for (pageIndex = startPageIndex; pageIndex <= endPageIndex; pageIndex++) {
                    if (Thread.interrupted()) {
                        throw new ExportInterruptedException();
                    }

                    page = pages.get(pageIndex);

                    exportPage(page);

                    if (reportIndex < items.size() - 1 || pageIndex < endPageIndex) {
                        writer.write("\n");
                    }
                }
            }
        }

        writer.write("\n}");

        boolean flushOutput = getCurrentConfiguration().isFlushOutput();
        if (flushOutput) {
            writer.flush();
        }
    }

    protected void exportPage(JRPrintPage page) throws IOException {
        Collection<JRPrintElement> elements = page.getElements();
        Boolean exportReportComponentsOnly = getCurrentConfiguration().isReportComponentsExportOnly();

        if (exportReportComponentsOnly == null) {
            exportReportComponentsOnly = false;
        }

        if (!exportReportComponentsOnly) {
            exportElements(elements);
            exportWebFonts();
            exportHyperlinks();
        }

        exportBookmarks();
        exportParts();

        JRExportProgressMonitor progressMonitor = getCurrentItemConfiguration().getProgressMonitor();
        if (progressMonitor != null) {
            progressMonitor.afterPageExport();
        }
    }

    protected void exportElements(Collection<JRPrintElement> elements) throws IOException {
        if (elements != null && elements.size() > 0) {
            for (Iterator<JRPrintElement> it = elements.iterator(); it.hasNext();) {
                JRPrintElement element = it.next();

                if (filter == null || filter.isToExport(element)) {
                    if (element instanceof JRPrintFrame) {
                        exportFrame((JRPrintFrame) element);
                    } else if (element instanceof JRGenericPrintElement) {
                        exportGenericElement((JRGenericPrintElement) element);
                    }
                }
            }
        }
    }

    protected void exportFrame(JRPrintFrame frame) throws IOException {
        exportElements(frame.getElements());
    }

    protected interface PrintBookmarkMixin {
        @JsonIgnore
        int getLevel();
    }

    protected void exportBookmarks() throws IOException {
        List<PrintBookmark> bookmarks = jasperPrint.getBookmarks();
        if (bookmarks != null && bookmarks.size() > 0) {
            if (gotFirstJsonFragment) {
                writer.write(",\n");
            } else {
                gotFirstJsonFragment = true;
            }

            writer.write("\"bkmrk_" + (bookmarks.hashCode() & 0x7FFFFFFF) + "\": ");
            writeBookmarks(bookmarks, writer, jacksonUtil);
        }
    }

    public static void writeBookmarks(List<PrintBookmark> bookmarks, Writer writer, JacksonUtil jacksonUtil)
            throws IOException {
        // exclude the methods marked with @JsonIgnore in PrintBookmarkMixin from PrintBookmark implementation
        jacksonUtil.getObjectMapper().addMixInAnnotations(PrintBookmark.class, PrintBookmarkMixin.class);

        writer.write("{");

        writer.write("\"id\": \"bkmrk_" + (bookmarks.hashCode() & 0x7FFFFFFF) + "\",");
        writer.write("\"type\": \"bookmarks\",");
        writer.write("\"bookmarks\": " + jacksonUtil.getJsonString(bookmarks));

        writer.write("}");
    }

    protected void exportParts() throws IOException {
        PrintParts parts = jasperPrint.getParts();

        if (parts != null && parts.hasParts()) {
            if (gotFirstJsonFragment) {
                writer.write(",\n");
            } else {
                gotFirstJsonFragment = true;
            }

            writer.write("\"parts_" + (parts.hashCode() & 0x7FFFFFFF) + "\": ");
            writeParts(jasperPrint, writer);
        }
    }

    public static void writeParts(JasperPrint jasperPrint, Writer writer) throws IOException {
        PrintParts parts = jasperPrint.getParts();
        writer.write("{");

        writer.write("\"id\": \"parts_" + (parts.hashCode() & 0x7FFFFFFF) + "\",");
        writer.write("\"type\": \"reportparts\",");
        writer.write("\"parts\": [");

        if (!parts.startsAtZero()) {
            writer.write("{\"idx\": 0, \"name\": \"");
            writer.write(JsonStringEncoder.getInstance().quoteAsString(jasperPrint.getName()));
            writer.write("\"}");
            if (parts.partCount() > 1) {
                writer.write(",");
            }
        }

        Iterator<Map.Entry<Integer, PrintPart>> it = parts.partsIterator();

        while (it.hasNext()) {
            Map.Entry<Integer, PrintPart> partsEntry = it.next();
            int idx = partsEntry.getKey();
            PrintPart part = partsEntry.getValue();

            writer.write("{\"idx\": " + idx + ", \"name\": \"");
            writer.write(JsonStringEncoder.getInstance().quoteAsString(part.getName()));
            writer.write("\"}");
            if (it.hasNext()) {
                writer.write(",");
            }
        }

        writer.write("]");
        writer.write("}");
    }

    protected void exportWebFonts() throws IOException {
        HtmlResourceHandler fontHandler = getExporterOutput().getFontHandler();
        ReportContext reportContext = getReportContext();

        if (fontHandler != null && reportContext != null
                && reportContext.containsParameter(REPORT_CONTEXT_PARAMETER_WEB_FONTS)) {
            Map<String, HtmlFontFamily> fontsToProcess = (Map<String, HtmlFontFamily>) reportContext
                    .getParameterValue(REPORT_CONTEXT_PARAMETER_WEB_FONTS);

            ObjectMapper mapper = new ObjectMapper();
            ArrayNode webFonts = mapper.createArrayNode();

            for (HtmlFontFamily htmlFontFamily : fontsToProcess.values()) {
                ObjectNode objNode = mapper.createObjectNode();
                objNode.put("id", htmlFontFamily.getId());
                objNode.put("path", fontHandler.getResourcePath(htmlFontFamily.getId()));
                webFonts.add(objNode);
            }

            if (gotFirstJsonFragment) {
                writer.write(",\n");
            } else {
                gotFirstJsonFragment = true;
            }
            writer.write("\"webfonts_" + (webFonts.hashCode() & 0x7FFFFFFF) + "\": {");

            writer.write("\"id\": \"webfonts_" + (webFonts.hashCode() & 0x7FFFFFFF) + "\",");
            writer.write("\"type\": \"webfonts\",");
            writer.write("\"webfonts\": " + jacksonUtil.getJsonString(webFonts));

            writer.write("}");
        }
    }

    protected void exportHyperlinks() throws IOException {
        ReportContext reportContext = getReportContext();
        String hyperlinksParameter = "net.sf.jasperreports.html.hyperlinks";
        if (reportContext != null && reportContext.containsParameter(hyperlinksParameter)) {
            List<HyperlinkData> contextHyperlinksData = (List<HyperlinkData>) reportContext
                    .getParameterValue(hyperlinksParameter);
            hyperlinksData.addAll(contextHyperlinksData);
        }
        if (hyperlinksData.size() > 0) {
            String id = "hyperlinks_" + (hyperlinksData.hashCode() & 0x7FFFFFFF);
            if (gotFirstJsonFragment) {
                writer.write(",\n");
            } else {
                gotFirstJsonFragment = true;
            }
            writer.write("\"" + id + "\": {");

            writer.write("\"id\": \"" + id + "\",");
            writer.write("\"type\": \"hyperlinks\",");
            writer.write("\"hyperlinks\": ");

            ObjectMapper mapper = new ObjectMapper();
            ArrayNode hyperlinkArray = mapper.createArrayNode();

            for (HyperlinkData hd : hyperlinksData) {
                JRPrintHyperlink hyperlink = hd.getHyperlink();
                ObjectNode hyperlinkNode = jacksonUtil.hyperlinkToJsonObject(hyperlink);

                jacksonUtil.addProperty(hyperlinkNode, "id", hd.getId());
                jacksonUtil.addProperty(hyperlinkNode, "href", hd.getHref());
                jacksonUtil.addProperty(hyperlinkNode, "selector", hd.getSelector());

                hyperlinkArray.add(hyperlinkNode);
            }

            writer.write(jacksonUtil.getJsonString(hyperlinkArray));
            writer.write("}");
        }
    }

    /**
     *
     */
    protected void exportGenericElement(JRGenericPrintElement element) throws IOException {
        GenericElementJsonHandler handler = (GenericElementJsonHandler) GenericElementHandlerEnviroment
                .getInstance(getJasperReportsContext())
                .getElementHandler(element.getGenericType(), JSON_EXPORTER_KEY);

        if (handler != null) {
            String fragment = handler.getJsonFragment(exporterContext, element);
            if (fragment != null && !fragment.isEmpty()) {
                if (gotFirstJsonFragment) {
                    writer.write(",\n");
                } else {
                    gotFirstJsonFragment = true;
                }
                writer.write(fragment);
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("No JSON generic element handler for " + element.getGenericType());
            }
        }
    }

    /**
     * 
     */
    protected String resolveHyperlinkURL(int reportIndex, JRPrintHyperlink link) {
        String href = null;

        Boolean ignoreHyperlink = HyperlinkUtil
                .getIgnoreHyperlink(HtmlReportConfiguration.PROPERTY_IGNORE_HYPERLINK, link);
        if (ignoreHyperlink == null) {
            ignoreHyperlink = getCurrentItemConfiguration().isIgnoreHyperlink();
        }

        if (!ignoreHyperlink) {
            JRHyperlinkProducer customHandler = getHyperlinkProducer(link);
            if (customHandler == null) {
                switch (link.getHyperlinkTypeValue()) {
                case REFERENCE: {
                    if (link.getHyperlinkReference() != null) {
                        href = link.getHyperlinkReference();
                    }
                    break;
                }
                case LOCAL_ANCHOR: {
                    if (link.getHyperlinkAnchor() != null) {
                        href = "#" + link.getHyperlinkAnchor();
                    }
                    break;
                }
                case LOCAL_PAGE: {
                    if (link.getHyperlinkPage() != null) {
                        href = "#" + HtmlExporter.JR_PAGE_ANCHOR_PREFIX + reportIndex + "_"
                                + link.getHyperlinkPage().toString();
                    }
                    break;
                }
                case REMOTE_ANCHOR: {
                    if (link.getHyperlinkReference() != null && link.getHyperlinkAnchor() != null) {
                        href = link.getHyperlinkReference() + "#" + link.getHyperlinkAnchor();
                    }
                    break;
                }
                case REMOTE_PAGE: {
                    if (link.getHyperlinkReference() != null && link.getHyperlinkPage() != null) {
                        href = link.getHyperlinkReference() + "#" + HtmlExporter.JR_PAGE_ANCHOR_PREFIX + "0_"
                                + link.getHyperlinkPage().toString();
                    }
                    break;
                }
                case NONE:
                default: {
                    break;
                }
                }
            } else {
                href = customHandler.getHyperlink(link);
            }
        }

        return href;
    }

    /**
     *
     */
    public void addHyperlinkData(HyperlinkData hyperlinkData) {
        this.hyperlinksData.add(hyperlinkData);
    }

    /**
     *
     */
    public void addFontFamily(HtmlFontFamily htmlFontFamily) {
        ReportContext reportContext = getReportContext();
        if (reportContext != null) {
            Map<String, HtmlFontFamily> fontsToProcess = (Map<String, HtmlFontFamily>) reportContext
                    .getParameterValue(REPORT_CONTEXT_PARAMETER_WEB_FONTS);

            if (fontsToProcess == null) {
                fontsToProcess = new HashMap<String, HtmlFontFamily>();
                reportContext.setParameterValue(REPORT_CONTEXT_PARAMETER_WEB_FONTS, fontsToProcess);
            }

            fontsToProcess.put(htmlFontFamily.getId(), htmlFontFamily);
        }
    }

    protected class ExporterContext extends BaseExporterContext implements JsonExporterContext {
        @Override
        public String getHyperlinkURL(JRPrintHyperlink link) {
            return resolveHyperlinkURL(reportIndex, link);
        }
    }

}