net.bull.javamelody.internal.web.pdf.PdfCounterReport.java Source code

Java tutorial

Introduction

Here is the source code for net.bull.javamelody.internal.web.pdf.PdfCounterReport.java

Source

/*
 * Copyright 2008-2017 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.internal.web.pdf;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.lowagie.text.BadElementException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;

import net.bull.javamelody.internal.common.I18N;
import net.bull.javamelody.internal.model.Collector;
import net.bull.javamelody.internal.model.Counter;
import net.bull.javamelody.internal.model.CounterRequest;
import net.bull.javamelody.internal.model.CounterRequestAggregation;
import net.bull.javamelody.internal.model.JRobin;
import net.bull.javamelody.internal.model.Range;

/**
 * Partie du rapport pdf pour un compteur.
 * @author Emeric Vernat
 */
class PdfCounterReport extends PdfAbstractTableReport {
    private final Collector collector;
    private final Counter counter;
    private final Range range;
    private final boolean includeGraph;
    private final CounterRequestAggregation counterRequestAggregation;
    private final DecimalFormat systemErrorFormat = I18N.createPercentFormat();
    private final DecimalFormat integerFormat = I18N.createIntegerFormat();
    private final Font infoCellFont = PdfFonts.INFO_CELL.getFont();
    private final Font warningCellFont = PdfFonts.WARNING_CELL.getFont();
    private final Font severeCellFont = PdfFonts.SEVERE_CELL.getFont();
    private final Font normalFont = PdfFonts.NORMAL.getFont();

    PdfCounterReport(Collector collector, Counter counter, Range range, boolean includeGraph, Document document) {
        super(document);
        assert collector != null;
        assert counter != null;
        assert range != null;
        this.collector = collector;
        this.counter = counter;
        this.range = range;
        this.includeGraph = includeGraph;
        this.counterRequestAggregation = new CounterRequestAggregation(counter);
    }

    @Override
    void toPdf() throws DocumentException, IOException {
        final List<CounterRequest> requests = counterRequestAggregation.getRequests();
        if (requests.isEmpty()) {
            writeNoRequests();
        } else if (isErrorAndNotJobCounter()) {
            // il y a au moins une "request" d'erreur puisque la liste n'est pas vide
            assert !requests.isEmpty();
            final List<CounterRequest> summaryRequest = Collections.singletonList(requests.get(0));
            writeRequests(counter.getChildCounterName(), summaryRequest);
        } else {
            // 1. synthse
            final CounterRequest globalRequest = counterRequestAggregation.getGlobalRequest();
            final List<CounterRequest> summaryRequests = Arrays.asList(globalRequest,
                    counterRequestAggregation.getWarningRequest(), counterRequestAggregation.getSevereRequest());
            writeRequests(counter.getChildCounterName(), summaryRequests);
        }
    }

    String getCounterName() {
        return counter.getName();
    }

    String getCounterIconName() {
        return counter.getIconName();
    }

    boolean isErrorCounter() {
        return counter.isErrorCounter();
    }

    private boolean isJobCounter() {
        return counter.isJobCounter();
    }

    private boolean isErrorAndNotJobCounter() {
        return isErrorCounter() && !isJobCounter();
    }

    void writeRequestDetails() throws DocumentException, IOException {
        // dtails des requtes
        final List<CounterRequest> requests = counterRequestAggregation.getRequests();
        if (requests.isEmpty()) {
            writeNoRequests();
        } else {
            // on n'inclue pas pour l'instant les graphs d'volution des requtes
            // pour des raisons de place et de volume
            writeRequests(counter.getChildCounterName(), requests);
        }
    }

    private void writeNoRequests() throws DocumentException {
        final String msg;
        if (isJobCounter()) {
            msg = "Aucun_job";
        } else if (isErrorCounter()) {
            msg = "Aucune_erreur";
        } else {
            msg = "Aucune_requete";
        }
        addToDocument(new Phrase(getString(msg), normalFont));
    }

    void writeErrorDetails() throws DocumentException {
        // dtails des erreurs
        new PdfCounterErrorReport(counter, getDocument()).toPdf();
    }

    void writeRequests(String childCounterName, List<CounterRequest> requestList)
            throws DocumentException, IOException {
        assert requestList != null;
        writeHeader(childCounterName);

        for (final CounterRequest request : requestList) {
            nextRow();
            writeRequest(request);
        }
        addTableToDocument();

        // dbit et liens
        writeFooter();
    }

    private void writeHeader(String childCounterName) throws DocumentException {
        final List<String> headers = createHeaders(childCounterName);
        final int[] relativeWidths = new int[headers.size()];
        Arrays.fill(relativeWidths, 0, headers.size(), 1);
        relativeWidths[0] = 10; // requte
        if (includeGraph) {
            relativeWidths[0] = 8;
            relativeWidths[1] = 2; // graph d'volution
        }

        initTable(headers, relativeWidths);
    }

    private List<String> createHeaders(String childCounterName) {
        final List<String> headers = new ArrayList<String>();
        headers.add(getRequestHeader());
        if (includeGraph) {
            headers.add(getString("Evolution"));
        }
        if (counterRequestAggregation.isTimesDisplayed()) {
            headers.add(getString("temps_cumule"));
            headers.add(getString("Hits"));
            headers.add(getString("Temps_moyen"));
            headers.add(getString("Temps_max"));
            headers.add(getString("Ecart_type"));
        } else {
            headers.add(getString("Hits"));
        }
        if (counterRequestAggregation.isCpuTimesDisplayed()) {
            headers.add(getString("temps_cpu_cumule"));
            headers.add(getString("Temps_cpu_moyen"));
        }
        if (counterRequestAggregation.isAllocatedKBytesDisplayed()) {
            headers.add(getString("Ko_alloues_moyens"));
        }
        if (!isErrorAndNotJobCounter()) {
            headers.add(getString("erreur_systeme"));
        }
        if (counterRequestAggregation.isResponseSizeDisplayed()) {
            headers.add(getString("Taille_moyenne"));
        }
        if (counterRequestAggregation.isChildHitsDisplayed()) {
            headers.add(getFormattedString("hits_fils_moyens", childCounterName));
            headers.add(getFormattedString("temps_fils_moyen", childCounterName));
        }
        return headers;
    }

    private String getRequestHeader() {
        if (isJobCounter()) {
            return getString("Job");
        } else if (isErrorCounter()) {
            return getString("Erreur");
        } else {
            return getString("Requete");
        }
    }

    private void writeFooter() throws DocumentException {
        final List<CounterRequest> requests = counterRequestAggregation.getRequests();
        final CounterRequest globalRequest = counterRequestAggregation.getGlobalRequest();
        // delta ni ngatif ni  0
        final long deltaMillis = Math.max(System.currentTimeMillis() - counter.getStartDate().getTime(), 1);
        final long hitsParMinute = 60 * 1000 * globalRequest.getHits() / deltaMillis;
        final String key;
        if (isJobCounter()) {
            key = "nb_jobs";
        } else if (isErrorCounter()) {
            key = "nb_erreurs";
        } else {
            key = "nb_requetes";
        }
        final Paragraph footer = new Paragraph(
                getFormattedString(key, integerFormat.format(hitsParMinute), integerFormat.format(requests.size())),
                normalFont);
        footer.setAlignment(Element.ALIGN_RIGHT);
        addToDocument(footer);
    }

    private void writeRequest(CounterRequest request) throws BadElementException, IOException {
        getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
        addCell(getShortRequestName(request));
        if (includeGraph) {
            writeRequestGraph(request);
        }
        getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
        final CounterRequest globalRequest = counterRequestAggregation.getGlobalRequest();
        if (counterRequestAggregation.isTimesDisplayed()) {
            addPercentageCell(request.getDurationsSum(), globalRequest.getDurationsSum());
            addCell(integerFormat.format(request.getHits()));
            final int mean = request.getMean();
            addCell(new Phrase(integerFormat.format(mean), getSlaFont(mean)));
            addCell(integerFormat.format(request.getMaximum()));
            addCell(integerFormat.format(request.getStandardDeviation()));
        } else {
            addCell(integerFormat.format(request.getHits()));
        }
        if (counterRequestAggregation.isCpuTimesDisplayed()) {
            addPercentageCell(request.getCpuTimeSum(), globalRequest.getCpuTimeSum());
            final int cpuTimeMean = request.getCpuTimeMean();
            addCell(new Phrase(integerFormat.format(cpuTimeMean), getSlaFont(cpuTimeMean)));
        }
        if (counterRequestAggregation.isAllocatedKBytesDisplayed()) {
            final long allocatedKBytesMean = request.getAllocatedKBytesMean();
            addCell(integerFormat.format(allocatedKBytesMean));
        }
        if (!isErrorAndNotJobCounter()) {
            addCell(systemErrorFormat.format(request.getSystemErrorPercentage()));
        }
        if (counterRequestAggregation.isResponseSizeDisplayed()) {
            addCell(integerFormat.format(request.getResponseSizeMean() / 1024));
        }
        if (counterRequestAggregation.isChildHitsDisplayed()) {
            addCell(integerFormat.format(request.getChildHitsMean()));
            addCell(integerFormat.format(request.getChildDurationsMean()));
        }
    }

    private String getShortRequestName(CounterRequest request) {
        final String name = request.getName();
        if (name.length() > 1000) {
            // si la requte fait plus de 1000 caractres, on la coupe pour y voir quelque chose
            return name.substring(0, 1000) + "...";
        }
        return name;
    }

    private void writeRequestGraph(CounterRequest request) throws BadElementException, IOException {
        final JRobin jrobin = collector.getJRobin(request.getId());
        if (jrobin == null) {
            addCell("");
        } else {
            final byte[] img = jrobin.graph(range, 100, 50);
            final Image image = Image.getInstance(img);
            image.scalePercent(50);
            addCell(image);
        }
    }

    Font getSlaFont(int mean) {
        final Font font;
        if (mean < counterRequestAggregation.getWarningThreshold() || mean == 0) {
            // si cette moyenne est <  la moyenne globale + 1 cart-type (paramtrable), c'est bien
            font = infoCellFont;
        } else if (mean < counterRequestAggregation.getSevereThreshold()) {
            // sinon, si cette moyenne est <  la moyenne globale + 2 cart-types (paramtrable),
            // attention  cette requte qui est plus longue que les autres
            font = warningCellFont;
        } else {
            // sinon, (cette moyenne est >  la moyenne globale + 2 cart-types),
            // cette requte est trs longue par rapport aux autres ;
            // il peut tre opportun de l'optimiser si possible
            font = severeCellFont;
        }
        return font;
    }

    private void addPercentageCell(long dividende, long diviseur) {
        if (diviseur == 0) {
            addCell("0");
        } else {
            addCell(integerFormat.format(100 * dividende / diviseur));
        }
    }
}