/*
* 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;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import net.bull.javamelody.swing.table.MDefaultTableCellRenderer;
import net.bull.javamelody.swing.table.MIntegerTableCellRenderer;
import net.bull.javamelody.swing.table.MTable;
import net.bull.javamelody.swing.table.MTableScrollPane;
/**
* Panel des statistiques.
* @author Emeric Vernat
*/
class StatisticsTablePanel extends MelodyPanel {
static final Color DARKER_GREEN = Color.GREEN.darker();
static final Font LABEL_BOLD_FONT = new JLabel().getFont().deriveFont(Font.BOLD);
static final Font LABEL_PLAIN_FONT = new JLabel().getFont().deriveFont(Font.PLAIN);
private static final long serialVersionUID = 1L;
@SuppressWarnings("all")
private final CounterRequestAggregation counterRequestAggregation;
private final Counter counter;
private final MTable<CounterRequest> table;
private static final class ResponseSizeMeanTableCellRenderer extends MIntegerTableCellRenderer {
private static final long serialVersionUID = 1L;
ResponseSizeMeanTableCellRenderer() {
super();
}
@Override
public void setValue(final Object value) {
super.setValue((Integer) value / 1024);
}
}
private class MeanTableCellRenderer extends MIntegerTableCellRenderer {
private static final long serialVersionUID = 1L;
MeanTableCellRenderer() {
super();
}
@Override
public void setValue(Object value) {
final Integer mean = (Integer) value;
final CounterRequestAggregation myCounterRequestAggregation = getCounterRequestAggregation();
setStyleBasedOnThresholds(this, mean, myCounterRequestAggregation);
super.setValue(mean);
}
}
private class DurationPercentageTableCellRenderer extends MDefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
DurationPercentageTableCellRenderer() {
super();
setHorizontalAlignment(SwingConstants.RIGHT);
}
@Override
public void setValue(final Object value) {
final CounterRequest globalRequest = getCounterRequestAggregation().getGlobalRequest();
if (globalRequest.getDurationsSum() == 0) {
setText("0");
} else {
setText(String.valueOf(100 * (Long) value / globalRequest.getDurationsSum()));
}
}
}
private class CpuPercentageTableCellRenderer extends MDefaultTableCellRenderer {
private static final long serialVersionUID = 1L;
CpuPercentageTableCellRenderer() {
super();
setHorizontalAlignment(SwingConstants.RIGHT);
}
@Override
public void setValue(final Object value) {
final CounterRequest globalRequest = getCounterRequestAggregation().getGlobalRequest();
if (globalRequest.getCpuTimeSum() == 0) {
setText("0");
} else {
setText(String.valueOf(100 * (Long) value / globalRequest.getCpuTimeSum()));
}
}
}
StatisticsTablePanel(RemoteCollector remoteCollector, Counter counter,
CounterRequestAggregation counterRequestAggregation, boolean includeGraph) {
super(remoteCollector);
assert counter != null;
assert counterRequestAggregation != null;
this.counter = counter;
this.counterRequestAggregation = counterRequestAggregation;
if (includeGraph) {
this.table = new CounterRequestTable(remoteCollector);
} else {
this.table = new MTable<>();
}
addColumns();
final MTableScrollPane<CounterRequest> tableScrollPane = new MTableScrollPane<>(table);
add(tableScrollPane, BorderLayout.CENTER);
}
private void addColumns() {
final String nameColumnHeader;
if (isJobCounter()) {
nameColumnHeader = getString("Job");
} else if (isErrorCounter()) {
nameColumnHeader = getString("Erreur");
} else {
nameColumnHeader = getString("Requete");
}
table.addColumn("name", nameColumnHeader);
// MMultiLineTableCellRenderer n'est pas défini ici pour la colonne "name"
// car les dimensions de certains scrollPane ne seraient pas corrects
final MIntegerTableCellRenderer meanCellRenderer = new MeanTableCellRenderer();
if (counterRequestAggregation.isTimesDisplayed()) {
table.addColumn("durationsSum", getString("temps_cumule"));
table.addColumn("hits", getString("Hits"));
table.addColumn("mean", getString("Temps_moyen"));
table.addColumn("maximum", getString("Temps_max"));
table.addColumn("standardDeviation", getString("Ecart_type"));
table.setColumnCellRenderer("durationsSum", new DurationPercentageTableCellRenderer());
table.setColumnCellRenderer("mean", meanCellRenderer);
} else {
table.addColumn("hits", getString("Hits"));
}
if (counterRequestAggregation.isCpuTimesDisplayed()) {
table.addColumn("cpuTimeSum", getString("temps_cpu_cumule"));
table.addColumn("cpuTimeMean", getString("Temps_cpu_moyen"));
table.setColumnCellRenderer("cpuTimeSum", new CpuPercentageTableCellRenderer());
table.setColumnCellRenderer("cpuTimeMean", meanCellRenderer);
}
if (!isErrorAndNotJobCounter()) {
table.addColumn("systemErrorPercentage", getString("erreur_systeme"));
}
if (counterRequestAggregation.isResponseSizeDisplayed()) {
table.addColumn("responseSizeMean", getString("Taille_moyenne"));
table.setColumnCellRenderer("responseSizeMean",
new ResponseSizeMeanTableCellRenderer());
}
if (counterRequestAggregation.isChildHitsDisplayed()) {
table.addColumn("childHitsMean",
getFormattedString("hits_fils_moyens", counter.getChildCounterName()));
table.addColumn("childDurationsMean",
getFormattedString("temps_fils_moyen", counter.getChildCounterName()));
}
}
void setList(List<CounterRequest> requests) {
table.setList(requests);
}
MTable<CounterRequest> getTable() {
return table;
}
CounterRequestAggregation getCounterRequestAggregation() {
return counterRequestAggregation;
}
private boolean isErrorCounter() {
return counter.isErrorCounter();
}
private boolean isJobCounter() {
return counter.isJobCounter();
}
private boolean isErrorAndNotJobCounter() {
return isErrorCounter() && !isJobCounter();
}
static void setStyleBasedOnThresholds(JComponent target, Integer duration,
CounterRequestAggregation aggregation) {
if (duration < aggregation.getWarningThreshold() || duration == 0) {
// si cette moyenne est < à la moyenne globale + 1 écart-type (paramétrable), c'est bien
// (si severeThreshold ou warningThreshold sont à 0 et mean à 0, c'est "info" et non "severe")
target.setForeground(DARKER_GREEN);
target.setFont(LABEL_PLAIN_FONT);
} else if (duration < aggregation.getSevereThreshold()) {
// sinon, si cette moyenne est < à la moyenne globale + 2 écart-types (paramétrable),
// attention à cette requête qui est plus longue que les autres
target.setForeground(Color.ORANGE);
target.setFont(LABEL_BOLD_FONT);
} else {
// sinon, (cette moyenne est > à la moyenne globale + 2 écart-types),
// cette requête est très longue par rapport aux autres ;
// il peut être opportun de l'optimiser si possible
target.setForeground(Color.RED);
target.setFont(LABEL_BOLD_FONT);
}
}
}