/* * 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.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import javax.swing.JComponent; import javax.swing.JToolTip; import javax.swing.UIManager; import javax.swing.plaf.metal.MetalToolTipUI; import net.bull.javamelody.swing.table.MTable; /** * Tableau de requêtes avec graphiques en toolTip * @author Emeric Vernat */ class CounterRequestTable extends MTable<CounterRequest> { private static final long serialVersionUID = 1L; private static final int IMAGE_HEIGHT = 50; private static final int IMAGE_WIDTH = 100; @SuppressWarnings("all") private final RemoteCollector remoteCollector; @SuppressWarnings("all") private final Map<String, CounterRequest> counterRequestByRequestName = new HashMap<>(); @SuppressWarnings("all") private final Map<String, BufferedImage> requestChartByRequestName = new HashMap<>(); private class ImageToolTip extends JToolTip { private static final long serialVersionUID = 1L; ImageToolTip() { super(); setUI(new ImageToolTipUI()); } } private class ImageToolTipUI extends MetalToolTipUI { ImageToolTipUI() { super(); // parce que ImageToolTipUI hérite de MetalToolTipUI et non de SynthToolTipUI // on fixe la couleur pour la propriété "ToolTip.background" // sinon ce tooltip aura une moche couleur grise à la place d'un jaune beige // (quand il n'y pas d'image jrobin) UIManager.put("ToolTip.background", UIManager.getColor("info")); } @Override public void paint(Graphics g, JComponent c) { try { final String tipText = ((JToolTip) c).getTipText(); final BufferedImage image = getRequestChartByRequestName(tipText); // on affiche que l'image et pas le text dans le tooltip // FontMetrics metrics = c.getFontMetrics(g.getFont()); // g.setColor(c.getForeground()); // g.drawString(tipText, 1, 1); if (image != null) { g.drawImage(image, 0, 0, c); } else { super.paint(g, c); } } catch (final IOException e) { // s'il y a une erreur dans la récupération de l'image tant pis super.paint(g, c); } } @Override public Dimension getPreferredSize(JComponent c) { try { final String tipText = ((JToolTip) c).getTipText(); final BufferedImage image = getRequestChartByRequestName(tipText); if (image != null) { // pas besoin de calculer la dimension de l'image, puisqu'elle est fixée avant d'avoir l'image return new Dimension(image.getWidth(), image.getHeight()); } return super.getPreferredSize(c); } catch (final IOException e) { // s'il y a une erreur dans la récupération de l'image tant pis return super.getPreferredSize(c); } // FontMetrics metrics = c.getFontMetrics(c.getFont()); // String tipText = ((JToolTip) c).getTipText(); // BufferedImage image = getRequestChartByRequestName(tipText); // if (tipText == null) { // tipText = ""; // } // int width = SwingUtilities.computeStringWidth(metrics, tipText); // int height = metrics.getHeight() + image.getHeight(c); // // if (width < image.getWidth(c)) { // width = image.getWidth(c); // } // return new Dimension(width, height); } } CounterRequestTable(RemoteCollector remoteCollector) { super(); this.remoteCollector = remoteCollector; } static boolean isRequestGraphDisplayed(Counter parentCounter) { return !(parentCounter.isErrorCounter() && !parentCounter.isJobCounter()) && !parentCounter.isJspOrStrutsCounter(); } @Override public JToolTip createToolTip() { final ImageToolTip imageToolTip = new ImageToolTip(); imageToolTip.setComponent(this); return imageToolTip; } @Override public void setList(List<CounterRequest> requests) { super.setList(requests); requestChartByRequestName.clear(); counterRequestByRequestName.clear(); } BufferedImage getRequestChartByRequestName(String requestName) throws IOException { BufferedImage requestChart; if (requestChartByRequestName.containsKey(requestName)) { requestChart = requestChartByRequestName.get(requestName); } else { requestChart = null; final CounterRequest counterRequest = getCounterRequestByRequestName(requestName); if (counterRequest != null) { final byte[] imageData = remoteCollector.collectJRobin(counterRequest.getId(), IMAGE_WIDTH, IMAGE_HEIGHT); if (imageData != null) { requestChart = ImageIO.read(new ByteArrayInputStream(imageData)); // requestChart sera mis dans la map par le put ci-dessous } } // si on n'a pas trouvé la requête dans la liste des requêtes // ou si on n'arrive pas à charger l'image depuis le serveur // alors il y aura null mis comme image dans la map // et au moins on ne cherchera plus inutilement dans cette liste // ou on n'essayera plus à chaque fois de charger l'image depuis le serveur // et sinon il y aura une image dans la map si tout va bien requestChartByRequestName.put(requestName, requestChart); } return requestChart; } private CounterRequest getCounterRequestByRequestName(String requestName) { // si cela n'a pas déjà été fait précédemment, on met tous les résultats de cette méthode dans une map indexée // pour éviter de créer une ArrayList et de reparcourir toutes les requêtes à chaque fois if (counterRequestByRequestName.isEmpty()) { final List<CounterRequest> requests = getList(); for (final CounterRequest request : requests) { counterRequestByRequestName.put(request.getName(), request); } } return counterRequestByRequestName.get(requestName); } }