net.bull.javamelody.PdfRequestAndGraphDetailReport.java Source code

Java tutorial

Introduction

Here is the source code for net.bull.javamelody.PdfRequestAndGraphDetailReport.java

Source

/*
 * Copyright 2008-2016 by Emeric Vernat
 *
 *     This file is part of Java Melody.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.bull.javamelody;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.lowagie.text.Chunk;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;

/**
 * Rapport pdf pour le dtail d'une requte.
 * @author Emeric Vernat
 */
public class PdfRequestAndGraphDetailReport extends PdfAbstractTableReport {
    private final Collector collector;
    private final CollectorServer collectorServer;
    private final Range range;
    private final List<Counter> counters;
    private final String graphName;
    private final CounterRequest request;
    private final Map<String, CounterRequest> requestsById;
    private final PdfDocumentFactory pdfDocumentFactory;
    private final DecimalFormat systemErrorFormat = I18N.createPercentFormat();
    private final DecimalFormat nbExecutionsFormat = I18N.createPercentFormat();
    private final DecimalFormat integerFormat = I18N.createIntegerFormat();
    private final Font cellFont = PdfFonts.TABLE_CELL.getFont();
    private final Font boldFont = PdfFonts.BOLD.getFont();
    private final Font courierFont = FontFactory.getFont(FontFactory.COURIER, 5.5f, Font.NORMAL);

    PdfRequestAndGraphDetailReport(Collector collector, CollectorServer collectorServer, Range range,
            String graphName, PdfDocumentFactory pdfDocumentFactory, Document document) throws IOException {
        super(document);
        assert collector != null;
        assert range != null;
        assert graphName != null;
        assert pdfDocumentFactory != null;
        this.collector = collector;
        this.collectorServer = collectorServer;
        this.range = range;
        this.graphName = graphName;
        this.counters = collector.getRangeCounters(range);
        this.requestsById = mapAllRequestsById();
        this.request = requestsById.get(graphName);
        this.pdfDocumentFactory = pdfDocumentFactory;
    }

    private Map<String, CounterRequest> mapAllRequestsById() {
        final Map<String, CounterRequest> result = new HashMap<String, CounterRequest>();
        for (final Counter counter : counters) {
            for (final CounterRequest aRequest : counter.getRequests()) {
                result.put(aRequest.getId(), aRequest);
            }
        }
        return result;
    }

    @Override
    void toPdf() throws DocumentException, IOException {
        if (request != null) {
            writeHeader();

            writeRequests();

            addTableToDocument();

            if (JdbcWrapper.SINGLETON.getSqlCounter().isRequestIdFromThisCounter(request.getId())
                    && !request.getName().toLowerCase(Locale.ENGLISH).startsWith("alter ")) {
                // inutile d'essayer d'avoir le plan d'excution des requtes sql
                // telles que "alter session set ..." (cf issue 152)
                writeSqlRequestExplainPlan();
            }
        }

        if (isGraphDisplayed()) {
            writeGraph();
        }

        if (request != null && request.getStackTrace() != null) {
            final Paragraph paragraph = new Paragraph("\n", cellFont);
            paragraph.setIndentationLeft(20);
            paragraph.setIndentationRight(20);
            paragraph.add(new Phrase("Stack-trace\n", boldFont));
            paragraph.add(new Phrase(request.getStackTrace().replace("\t", "        "), cellFont));
            addToDocument(paragraph);
        }
    }

    private void writeHeader() throws DocumentException {
        final List<String> headers = createHeaders();
        final int[] relativeWidths = new int[headers.size()];
        Arrays.fill(relativeWidths, 0, headers.size(), 1);
        relativeWidths[0] = 8; // requte

        initTable(headers, relativeWidths);
    }

    private List<String> createHeaders() {
        final List<String> headers = new ArrayList<String>();
        headers.add(getString("Requete"));
        final boolean hasChildren = !request.getChildRequestsExecutionsByRequestId().isEmpty();
        if (hasChildren) {
            headers.add(getString("Hits_par_requete"));
        }
        headers.add(getString("Temps_moyen"));
        headers.add(getString("Temps_max"));
        headers.add(getString("Ecart_type"));
        headers.add(getString("Temps_cpu_moyen"));
        headers.add(getString("erreur_systeme"));
        final Counter parentCounter = getCounterByRequestId(request);
        final boolean allChildHitsDisplayed = parentCounter != null && parentCounter.getChildCounterName() != null
                && request.hasChildHits();
        if (allChildHitsDisplayed) {
            final String childCounterName = parentCounter.getChildCounterName();
            headers.add(getFormattedString("hits_fils_moyens", childCounterName));
            headers.add(getFormattedString("temps_fils_moyen", childCounterName));
        }
        return headers;
    }

    private void writeRequests() throws IOException, DocumentException {
        final Map<String, Long> childRequests = request.getChildRequestsExecutionsByRequestId();
        final boolean hasChildren = !childRequests.isEmpty();
        final Counter parentCounter = getCounterByRequestId(request);
        final boolean allChildHitsDisplayed = parentCounter != null && parentCounter.getChildCounterName() != null
                && request.hasChildHits();

        final PdfPCell defaultCell = getDefaultCell();
        defaultCell.setLeading(2, 1);
        defaultCell.setPaddingTop(0);

        nextRow();
        writeRequest(request, -1, allChildHitsDisplayed);

        if (hasChildren) {
            writeChildRequests(childRequests, allChildHitsDisplayed);
        }
    }

    private void writeChildRequests(Map<String, Long> childRequests, boolean allChildHitsDisplayed)
            throws IOException, DocumentException {
        for (final Map.Entry<String, Long> entry : childRequests.entrySet()) {
            final CounterRequest childRequest = requestsById.get(entry.getKey());
            if (childRequest != null) {
                nextRow();
                final Long nbExecutions = entry.getValue();
                final float executionsByRequest = (float) nbExecutions / request.getHits();
                writeRequest(childRequest, executionsByRequest, allChildHitsDisplayed);
            }
        }
    }

    private void writeRequest(CounterRequest childRequest, float executionsByRequest, boolean allChildHitsDisplayed)
            throws IOException, DocumentException {
        final PdfPCell defaultCell = getDefaultCell();
        defaultCell.setHorizontalAlignment(Element.ALIGN_LEFT);
        final Paragraph paragraph = new Paragraph(defaultCell.getLeading() + cellFont.getSize());
        if (executionsByRequest != -1) {
            paragraph.setIndentationLeft(5);
        }
        final Counter parentCounter = getCounterByRequestId(childRequest);
        if (parentCounter != null && parentCounter.getIconName() != null) {
            paragraph.add(new Chunk(getSmallImage(parentCounter.getIconName()), 0, -1));
        }
        paragraph.add(new Phrase(childRequest.getName(), cellFont));
        final PdfPCell requestCell = new PdfPCell();
        requestCell.addElement(paragraph);
        requestCell.setGrayFill(defaultCell.getGrayFill());
        requestCell.setPaddingTop(defaultCell.getPaddingTop());
        addCell(requestCell);

        defaultCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
        if (executionsByRequest != -1) {
            addCell(nbExecutionsFormat.format(executionsByRequest));
        } else {
            addCell("");
        }
        writeRequestValues(childRequest, allChildHitsDisplayed);
    }

    private void writeRequestValues(CounterRequest aRequest, boolean allChildHitsDisplayed) {
        final PdfPCell defaultCell = getDefaultCell();
        defaultCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
        addCell(integerFormat.format(aRequest.getMean()));
        addCell(integerFormat.format(aRequest.getMaximum()));
        addCell(integerFormat.format(aRequest.getStandardDeviation()));
        if (aRequest.getCpuTimeMean() >= 0) {
            addCell(integerFormat.format(aRequest.getCpuTimeMean()));
        } else {
            addCell("");
        }
        addCell(systemErrorFormat.format(aRequest.getSystemErrorPercentage()));
        if (allChildHitsDisplayed) {
            final boolean childHitsDisplayed = aRequest.hasChildHits();
            if (childHitsDisplayed) {
                addCell(integerFormat.format(aRequest.getChildHitsMean()));
            } else {
                addCell("");
            }
            if (childHitsDisplayed) {
                addCell(integerFormat.format(aRequest.getChildDurationsMean()));
            } else {
                addCell("");
            }
        }
    }

    private void writeGraph() throws IOException, DocumentException {
        final JRobin jrobin = collector.getJRobin(graphName);
        if (jrobin != null) {
            final byte[] img = jrobin.graph(range, 960, 400);
            final Image image = Image.getInstance(img);
            image.scalePercent(50);

            final PdfPTable table = new PdfPTable(1);
            table.setHorizontalAlignment(Element.ALIGN_CENTER);
            table.setWidthPercentage(100);
            table.getDefaultCell().setBorder(0);
            table.addCell("\n");
            table.addCell(image);
            table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
            table.addCell(new Phrase(getString("graph_units"), cellFont));
            addToDocument(table);
        } else {
            // just in case request is null and collector.getJRobin(graphName) is null, we must write something in the document
            addToDocument(new Phrase("\n", cellFont));
        }
    }

    private void writeSqlRequestExplainPlan() throws DocumentException {
        try {
            final String explainPlan;
            if (collectorServer == null) {
                explainPlan = DatabaseInformations.explainPlanFor(request.getName());
            } else {
                explainPlan = collectorServer.collectSqlRequestExplainPlan(collector.getApplication(),
                        request.getName());
            }
            if (explainPlan != null) {
                final Paragraph paragraph = new Paragraph("", cellFont);
                paragraph.add(new Phrase('\n' + getString("Plan_d_execution") + '\n', boldFont));
                paragraph.add(new Phrase(explainPlan, courierFont));
                addToDocument(paragraph);
            }
        } catch (final Exception e) {
            final Paragraph paragraph = new Paragraph("", cellFont);
            paragraph.add(new Phrase('\n' + getString("Plan_d_execution") + '\n', boldFont));
            paragraph.add(new Phrase(e.toString(), cellFont));
            addToDocument(paragraph);
        }
    }

    private Counter getCounterByRequestId(CounterRequest aRequest) {
        final String myRequestId = aRequest.getId();
        for (final Counter counter : counters) {
            if (counter.isRequestIdFromThisCounter(myRequestId)) {
                return counter;
            }
        }
        return null;
    }

    private boolean isGraphDisplayed() {
        return request == null || getCounterByRequestId(request) != null
                && HtmlCounterReport.isRequestGraphDisplayed(getCounterByRequestId(request))
                // on vrifie aussi que l'instance de jrobin existe pour faire le graph,
                // notamment si les statistiques ont t rinitialises, ce qui vide les instances de jrobin
                && collector.getJRobin(request.getId()) != null;
    }

    private Image getSmallImage(String resourceFileName) throws DocumentException, IOException {
        return pdfDocumentFactory.getSmallImage(resourceFileName);
    }
}