1 /* 2 * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.jconsole; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.io.*; 31 import java.lang.management.*; 32 import java.lang.reflect.*; 33 import java.util.*; 34 import java.util.concurrent.*; 35 36 import javax.accessibility.*; 37 import javax.management.*; 38 import javax.management.openmbean.CompositeData; 39 import javax.swing.*; 40 import javax.swing.border.*; 41 42 import sun.tools.jconsole.resources.Messages; 43 44 import static sun.tools.jconsole.Formatter.*; 45 import static sun.tools.jconsole.Utilities.*; 46 47 @SuppressWarnings("serial") 48 class MemoryTab extends Tab implements ActionListener, ItemListener { 49 JComboBox<Plotter> plotterChoice; 50 TimeComboBox timeComboBox; 51 JButton gcButton; 52 53 PlotterPanel plotterPanel; 54 JPanel bottomPanel; 55 HTMLPane details; 56 PoolChart poolChart; 57 58 ArrayList<Plotter> plotterList; 59 Plotter heapPlotter, nonHeapPlotter; 60 61 private MemoryOverviewPanel overviewPanel; 62 63 private static final String usedKey = "used"; 64 private static final String committedKey = "committed"; 65 private static final String maxKey = "max"; 66 private static final String thresholdKey = "threshold"; 67 private static final Color usedColor = Plotter.defaultColor; 68 private static final Color committedColor = null; 69 private static final Color maxColor = null; 70 private static final Color thresholdColor = Color.red; 71 72 /* 73 Hierarchy of panels and layouts for this tab: 74 75 MemoryTab (BorderLayout) 76 77 North: topPanel (BorderLayout) 78 79 Center: controlPanel (FlowLayout) 80 plotterChoice, timeComboBox 81 82 East: topRightPanel (FlowLayout) 83 gcButton 84 85 Center: plotterPanel 86 87 Center: plotter 88 89 South: bottomPanel (BorderLayout) 90 91 Center: details 92 East: poolChart 93 */ 94 95 96 public static String getTabName() { 97 return Messages.MEMORY; 98 } 99 100 public MemoryTab(VMPanel vmPanel) { 101 super(vmPanel, getTabName()); 102 103 setLayout(new BorderLayout(0, 0)); 104 setBorder(new EmptyBorder(4, 4, 3, 4)); 105 106 JPanel topPanel = new JPanel(new BorderLayout()); 107 plotterPanel = new PlotterPanel(null); 108 bottomPanel = new JPanel(new BorderLayout()); 109 110 add(topPanel, BorderLayout.NORTH); 111 add(plotterPanel, BorderLayout.CENTER); 112 113 JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 20, 5)); 114 topPanel.add(controlPanel, BorderLayout.CENTER); 115 116 // Plotter choice 117 plotterChoice = new JComboBox<Plotter>(); 118 plotterChoice.addItemListener(this); 119 controlPanel.add(new LabeledComponent(Messages.CHART_COLON, 120 Resources.getMnemonicInt(Messages.CHART_COLON), 121 plotterChoice)); 122 123 // Range control 124 timeComboBox = new TimeComboBox(); 125 controlPanel.add(new LabeledComponent(Messages.TIME_RANGE_COLON, 126 Resources.getMnemonicInt(Messages.TIME_RANGE_COLON), 127 timeComboBox)); 128 129 gcButton = new JButton(Messages.PERFORM_GC); 130 gcButton.setMnemonic(Resources.getMnemonicInt(Messages.PERFORM_GC)); 131 gcButton.addActionListener(this); 132 gcButton.setToolTipText(Messages.PERFORM_GC_TOOLTIP); 133 JPanel topRightPanel = new JPanel(); 134 topRightPanel.setBorder(new EmptyBorder(0, 65-8, 0, 70)); 135 topRightPanel.add(gcButton); 136 topPanel.add(topRightPanel, BorderLayout.AFTER_LINE_ENDS); 137 138 bottomPanel.setBorder(new CompoundBorder(new TitledBorder(Messages.DETAILS), 139 new EmptyBorder(10, 10, 10, 10))); 140 141 details = new HTMLPane(); 142 setAccessibleName(details, Messages.DETAILS); 143 bottomPanel.add(new JScrollPane(details), BorderLayout.CENTER); 144 145 poolChart = new PoolChart(); 146 bottomPanel.add(poolChart, BorderLayout.AFTER_LINE_ENDS); 147 } 148 149 150 private void createPlotters() throws IOException { 151 plotterList = new ArrayList<Plotter>(); 152 153 ProxyClient proxyClient = vmPanel.getProxyClient(); 154 155 heapPlotter = new Plotter(Plotter.Unit.BYTES) { 156 public String toString() { 157 return Messages.HEAP_MEMORY_USAGE; 158 } 159 }; 160 proxyClient.addWeakPropertyChangeListener(heapPlotter); 161 162 nonHeapPlotter = new Plotter(Plotter.Unit.BYTES) { 163 public String toString() { 164 return Messages.NON_HEAP_MEMORY_USAGE; 165 } 166 }; 167 168 setAccessibleName(heapPlotter, 169 Messages.MEMORY_TAB_HEAP_PLOTTER_ACCESSIBLE_NAME); 170 setAccessibleName(nonHeapPlotter, 171 Messages.MEMORY_TAB_NON_HEAP_PLOTTER_ACCESSIBLE_NAME); 172 173 proxyClient.addWeakPropertyChangeListener(nonHeapPlotter); 174 175 heapPlotter.createSequence(usedKey, Messages.USED, usedColor, true); 176 heapPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false); 177 heapPlotter.createSequence(maxKey, Messages.MAX, maxColor, false); 178 179 nonHeapPlotter.createSequence(usedKey, Messages.USED, usedColor, true); 180 nonHeapPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false); 181 nonHeapPlotter.createSequence(maxKey, Messages.MAX, maxColor, false); 182 183 plotterList.add(heapPlotter); 184 plotterList.add(nonHeapPlotter); 185 186 // Now add memory pools 187 Map<ObjectName, MBeanInfo> mBeanMap = proxyClient.getMBeans("java.lang"); 188 Set<ObjectName> keys = mBeanMap.keySet(); 189 ObjectName[] objectNames = keys.toArray(new ObjectName[keys.size()]); 190 ArrayList<PoolPlotter> nonHeapPlotters = new ArrayList<PoolPlotter>(2); 191 for (ObjectName objectName : objectNames) { 192 String type = objectName.getKeyProperty("type"); 193 if (type.equals("MemoryPool")) { 194 String name = Resources.format(Messages.MEMORY_POOL_LABEL, 195 objectName.getKeyProperty("name")); 196 // Heap or non-heap? 197 boolean isHeap = false; 198 AttributeList al = 199 proxyClient.getAttributes(objectName, 200 new String[] { "Type" }); 201 if (al.size() > 0) { 202 isHeap = MemoryType.HEAP.name().equals(((Attribute)al.get(0)).getValue()); 203 } 204 PoolPlotter poolPlotter = new PoolPlotter(objectName, name, isHeap); 205 proxyClient.addWeakPropertyChangeListener(poolPlotter); 206 207 poolPlotter.createSequence(usedKey, Messages.USED, usedColor, true); 208 poolPlotter.createSequence(committedKey, Messages.COMMITTED, committedColor, false); 209 poolPlotter.createSequence(maxKey, Messages.MAX, maxColor, false); 210 poolPlotter.createSequence(thresholdKey, Messages.THRESHOLD, thresholdColor, false); 211 poolPlotter.setUseDashedTransitions(thresholdKey, true); 212 213 if (isHeap) { 214 plotterList.add(poolPlotter); 215 } else { 216 // Will be added to plotterList below 217 nonHeapPlotters.add(poolPlotter); 218 } 219 } 220 } 221 // Add non-heap plotters last 222 for (PoolPlotter poolPlotter : nonHeapPlotters) { 223 plotterList.add(poolPlotter); 224 } 225 } 226 227 228 public void itemStateChanged(ItemEvent ev) { 229 if (ev.getStateChange() == ItemEvent.SELECTED) { 230 Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); 231 plotterPanel.setPlotter(plotter); 232 } 233 } 234 235 public void gc() { 236 new Thread("MemoryPanel.gc") { 237 public void run() { 238 ProxyClient proxyClient = vmPanel.getProxyClient(); 239 try { 240 proxyClient.getMemoryMXBean().gc(); 241 } catch (UndeclaredThrowableException e) { 242 proxyClient.markAsDead(); 243 } catch (IOException e) { 244 // Ignore 245 } 246 } 247 }.start(); 248 } 249 250 public SwingWorker<?, ?> newSwingWorker() { 251 return new SwingWorker<Boolean, Object>() { 252 private long[] used, committed, max, threshold; 253 private long timeStamp; 254 private String detailsStr; 255 private boolean initialRun = false; 256 257 public Boolean doInBackground() { 258 ProxyClient proxyClient = vmPanel.getProxyClient(); 259 260 if (plotterList == null) { 261 try { 262 createPlotters(); 263 } catch (UndeclaredThrowableException e) { 264 proxyClient.markAsDead(); 265 return false; 266 } catch (final IOException ex) { 267 return false; 268 } 269 initialRun = true; 270 } 271 272 int n = plotterList.size(); 273 used = new long[n]; 274 committed = new long[n]; 275 max = new long[n]; 276 threshold = new long[n]; 277 timeStamp = System.currentTimeMillis(); 278 279 for (int i = 0; i < n; i++) { 280 Plotter plotter = plotterList.get(i); 281 MemoryUsage mu = null; 282 used[i] = -1L; 283 threshold[i] = -1L; 284 285 try { 286 if (plotter instanceof PoolPlotter) { 287 PoolPlotter poolPlotter = (PoolPlotter)plotter; 288 ObjectName objectName = poolPlotter.objectName; 289 AttributeList al = 290 proxyClient.getAttributes(objectName, 291 new String[] { "Usage", "UsageThreshold" }); 292 if (al.size() > 0) { 293 CompositeData cd = (CompositeData)((Attribute)al.get(0)).getValue(); 294 mu = MemoryUsage.from(cd); 295 296 if (al.size() > 1) { 297 threshold[i] = (Long)((Attribute)al.get(1)).getValue(); 298 } 299 } 300 } else if (plotter == heapPlotter) { 301 mu = proxyClient.getMemoryMXBean().getHeapMemoryUsage(); 302 } else if (plotter == nonHeapPlotter) { 303 mu = proxyClient.getMemoryMXBean().getNonHeapMemoryUsage(); 304 } 305 } catch (UndeclaredThrowableException e) { 306 proxyClient.markAsDead(); 307 return false; 308 } catch (IOException ex) { 309 // Skip this plotter 310 } 311 312 if (mu != null) { 313 used[i] = mu.getUsed(); 314 committed[i] = mu.getCommitted(); 315 max[i] = mu.getMax(); 316 } 317 } 318 detailsStr = formatDetails(); 319 320 return true; 321 } 322 323 protected void done() { 324 try { 325 if (!get()) { 326 return; 327 } 328 } catch (InterruptedException ex) { 329 return; 330 } catch (ExecutionException ex) { 331 if (JConsole.isDebug()) { 332 ex.printStackTrace(); 333 } 334 return; 335 } 336 337 if (initialRun) { 338 // Add Memory Pools 339 for (Plotter p : plotterList) { 340 plotterChoice.addItem(p); 341 timeComboBox.addPlotter(p); 342 } 343 add(bottomPanel, BorderLayout.SOUTH); 344 } 345 346 347 int n = plotterList.size(); 348 int poolCount = 0; 349 350 for (int i = 0; i < n; i++) { 351 Plotter plotter = plotterList.get(i); 352 if (used[i] >= 0L) { 353 if (plotter instanceof PoolPlotter) { 354 plotter.addValues(timeStamp, used[i], committed[i], max[i], threshold[i]); 355 if (threshold[i] > 0L) { 356 plotter.setIsPlotted(thresholdKey, true); 357 } 358 poolChart.setValue(poolCount++, (PoolPlotter)plotter, 359 used[i], threshold[i], max[i]); 360 } else { 361 plotter.addValues(timeStamp, used[i], committed[i], max[i]); 362 } 363 364 if (plotter == heapPlotter && overviewPanel != null) { 365 overviewPanel.getPlotter().addValues(timeStamp, used[i]); 366 overviewPanel.updateMemoryInfo(used[i], committed[i], max[i]); 367 } 368 } 369 } 370 details.setText(detailsStr); 371 } 372 }; 373 } 374 375 private String formatDetails() { 376 ProxyClient proxyClient = vmPanel.getProxyClient(); 377 if (proxyClient.isDead()) { 378 return ""; 379 } 380 381 String text = "<table cellspacing=0 cellpadding=0>"; 382 383 Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); 384 if (plotter == null) { 385 return ""; 386 } 387 388 //long time = plotter.getLastTimeStamp(); 389 long time = System.currentTimeMillis(); 390 String timeStamp = formatDateTime(time); 391 text += newRow(Messages.TIME, timeStamp); 392 393 long used = plotter.getLastValue(usedKey); 394 long committed = plotter.getLastValue(committedKey); 395 long max = plotter.getLastValue(maxKey); 396 long threshold = plotter.getLastValue(thresholdKey); 397 398 text += newRow(Messages.USED, formatKBytes(used)); 399 if (committed > 0L) { 400 text += newRow(Messages.COMMITTED, formatKBytes(committed)); 401 } 402 if (max > 0L) { 403 text += newRow(Messages.MAX, formatKBytes(max)); 404 } 405 if (threshold > 0L) { 406 text += newRow(Messages.USAGE_THRESHOLD, formatKBytes(threshold)); 407 } 408 409 try { 410 Collection<GarbageCollectorMXBean> garbageCollectors = 411 proxyClient.getGarbageCollectorMXBeans(); 412 413 boolean descPrinted = false; 414 for (GarbageCollectorMXBean garbageCollectorMBean : garbageCollectors) { 415 String gcName = garbageCollectorMBean.getName(); 416 long gcCount = garbageCollectorMBean.getCollectionCount(); 417 long gcTime = garbageCollectorMBean.getCollectionTime(); 418 String str = Resources.format(Messages.GC_TIME_DETAILS, justify(formatTime(gcTime), 14), 419 gcName, 420 String.format("%,d",gcCount)); 421 if (!descPrinted) { 422 text += newRow(Messages.GC_TIME, str); 423 descPrinted = true; 424 } else { 425 text += newRow(null, str); 426 } 427 } 428 } catch (IOException e) { 429 } 430 431 return text; 432 } 433 434 public void actionPerformed(ActionEvent ev) { 435 Object src = ev.getSource(); 436 if (src == gcButton) { 437 gc(); 438 } 439 } 440 441 private class PoolPlotter extends Plotter { 442 ObjectName objectName; 443 String name; 444 boolean isHeap; 445 long value, threshold, max; 446 int barX; 447 448 public PoolPlotter(ObjectName objectName, String name, boolean isHeap) { 449 super(Plotter.Unit.BYTES); 450 451 this.objectName = objectName; 452 this.name = name; 453 this.isHeap = isHeap; 454 455 setAccessibleName(this, 456 Resources.format(Messages.MEMORY_TAB_POOL_PLOTTER_ACCESSIBLE_NAME, 457 name)); 458 } 459 460 461 public String toString() { 462 return name; 463 } 464 } 465 466 private class PoolChart extends BorderedComponent 467 implements Accessible, MouseListener { 468 final int height = 150; 469 final int leftMargin = 50; 470 final int rightMargin = 23; 471 final int bottomMargin = 35; 472 final int barWidth = 22; 473 final int barGap = 3; 474 final int groupGap = 8; 475 final int barHeight = height * 2 / 3; 476 477 final Color greenBar = new Color(100, 255, 100); 478 final Color greenBarBackground = new Color(210, 255, 210); 479 final Color redBarBackground = new Color(255, 210, 210); 480 481 Font smallFont = null; 482 483 ArrayList<PoolPlotter> poolPlotters = new ArrayList<PoolPlotter>(5); 484 485 int nHeapPools = 0; 486 int nNonHeapPools = 0; 487 Rectangle heapRect = new Rectangle(leftMargin, height - bottomMargin + 6, barWidth, 20); 488 Rectangle nonHeapRect = new Rectangle(leftMargin + groupGap, height - bottomMargin + 6, barWidth, 20); 489 490 public PoolChart() { 491 super(null, null); 492 493 setFocusable(true); 494 addMouseListener(this); 495 ToolTipManager.sharedInstance().registerComponent(this); 496 } 497 498 public void setValue(int poolIndex, PoolPlotter poolPlotter, 499 long value, long threshold, long max) { 500 poolPlotter.value = value; 501 poolPlotter.threshold = threshold; 502 poolPlotter.max = max; 503 504 if (poolIndex == poolPlotters.size()) { 505 poolPlotters.add(poolPlotter); 506 if (poolPlotter.isHeap) { 507 poolPlotter.barX = nHeapPools * (barWidth + barGap); 508 nHeapPools++; 509 heapRect.width = nHeapPools * barWidth + (nHeapPools - 1) * barGap; 510 nonHeapRect.x = leftMargin + heapRect.width + groupGap; 511 } else { 512 poolPlotter.barX = nonHeapRect.x - leftMargin + nNonHeapPools * (barWidth + barGap); 513 nNonHeapPools++; 514 nonHeapRect.width = nNonHeapPools * barWidth + (nNonHeapPools - 1) * barGap; 515 } 516 } else { 517 poolPlotters.set(poolIndex, poolPlotter); 518 } 519 repaint(); 520 } 521 522 private void paintPoolBar(Graphics g, PoolPlotter poolPlotter) { 523 Rectangle barRect = getBarRect(poolPlotter); 524 g.setColor(Color.gray); 525 g.drawRect(barRect.x, barRect.y, barRect.width, barRect.height); 526 527 long value = poolPlotter.value; 528 long max = poolPlotter.max; 529 if (max > 0L) { 530 g.translate(barRect.x, barRect.y); 531 532 // Paint green background 533 g.setColor(greenBarBackground); 534 g.fillRect(1, 1, barRect.width - 1, barRect.height - 1); 535 536 int greenHeight = (int)(value * barRect.height / max); 537 long threshold = poolPlotter.threshold; 538 if (threshold > 0L) { 539 int redHeight = (int)(threshold * barRect.height / max); 540 541 // Paint red background 542 g.setColor(redBarBackground); 543 g.fillRect(1, 1, barRect.width - 1, barRect.height - redHeight); 544 545 if (value > threshold) { 546 // Over threshold, paint red bar 547 g.setColor(thresholdColor); 548 g.fillRect(1, barRect.height - greenHeight, 549 barRect.width - 1, greenHeight - redHeight); 550 greenHeight = redHeight; 551 } 552 } 553 554 // Paint green bar 555 g.setColor(greenBar); 556 g.fillRect(1, barRect.height - greenHeight, 557 barRect.width - 1, greenHeight); 558 559 g.translate(-barRect.x, -barRect.y); 560 } 561 } 562 563 public void paintComponent(Graphics g) { 564 super.paintComponent(g); 565 566 if (poolPlotters.size() == 0) { 567 return; 568 } 569 570 if (smallFont == null) { 571 smallFont = g.getFont().deriveFont(9.0F); 572 } 573 574 // Paint background for chart area 575 g.setColor(getBackground()); 576 Rectangle r = g.getClipBounds(); 577 g.fillRect(r.x, r.y, r.width, r.height); 578 579 g.setFont(smallFont); 580 FontMetrics fm = g.getFontMetrics(); 581 int fontDescent = fm.getDescent(); 582 583 // Paint percentage axis 584 g.setColor(getForeground()); 585 for (int pc : new int[] { 0, 25, 50, 75, 100 }) { 586 String str = pc + "% --"; 587 g.drawString(str, 588 leftMargin - fm.stringWidth(str) - 4, 589 height - bottomMargin - (pc * barHeight / 100) + fontDescent + 1); 590 } 591 592 for (PoolPlotter poolPlotter : poolPlotters) { 593 paintPoolBar(g, poolPlotter); 594 } 595 596 g.setColor(Color.gray); 597 g.drawRect(heapRect.x, heapRect.y, heapRect.width, heapRect.height); 598 g.drawRect(nonHeapRect.x, nonHeapRect.y, nonHeapRect.width, nonHeapRect.height); 599 600 Color heapColor = greenBar; 601 Color nonHeapColor = greenBar; 602 603 604 for (PoolPlotter poolPlotter : poolPlotters) { 605 if (poolPlotter.threshold > 0L && poolPlotter.value > poolPlotter.threshold) { 606 if (poolPlotter.isHeap) { 607 heapColor = thresholdColor; 608 } else { 609 nonHeapColor = thresholdColor; 610 } 611 } 612 } 613 g.setColor(heapColor); 614 g.fillRect(heapRect.x + 1, heapRect.y + 1, heapRect.width - 1, heapRect.height - 1); 615 g.setColor(nonHeapColor); 616 g.fillRect(nonHeapRect.x + 1, nonHeapRect.y + 1, nonHeapRect.width - 1, nonHeapRect.height - 1); 617 618 String str = Messages.HEAP; 619 int stringWidth = fm.stringWidth(str); 620 int x = heapRect.x + (heapRect.width - stringWidth) / 2; 621 int y = heapRect.y + heapRect.height - 6; 622 g.setColor(Color.white); 623 g.drawString(str, x-1, y-1); 624 g.drawString(str, x+1, y-1); 625 g.drawString(str, x-1, y+1); 626 g.drawString(str, x+1, y+1); 627 g.setColor(Color.black); 628 g.drawString(str, x, y); 629 630 str = Messages.NON_HEAP; 631 stringWidth = fm.stringWidth(str); 632 x = nonHeapRect.x + (nonHeapRect.width - stringWidth) / 2; 633 y = nonHeapRect.y + nonHeapRect.height - 6; 634 g.setColor(Color.white); 635 g.drawString(str, x-1, y-1); 636 g.drawString(str, x+1, y-1); 637 g.drawString(str, x-1, y+1); 638 g.drawString(str, x+1, y+1); 639 g.setColor(Color.black); 640 g.drawString(str, x, y); 641 642 // Highlight current plotter 643 g.setColor(Color.blue); 644 r = null; 645 Plotter plotter = (Plotter)plotterChoice.getSelectedItem(); 646 if (plotter == heapPlotter) { 647 r = heapRect; 648 } else if (plotter == nonHeapPlotter) { 649 r = nonHeapRect; 650 } else if (plotter instanceof PoolPlotter) { 651 r = getBarRect((PoolPlotter)plotter); 652 } 653 if (r != null) { 654 g.drawRect(r.x - 1, r.y - 1, r.width + 2, r.height + 2); 655 } 656 } 657 658 private Rectangle getBarRect(PoolPlotter poolPlotter) { 659 return new Rectangle(leftMargin + poolPlotter.barX, 660 height - bottomMargin - barHeight, 661 barWidth, barHeight); 662 } 663 664 public Dimension getPreferredSize() { 665 return new Dimension(nonHeapRect.x + nonHeapRect.width + rightMargin, 666 height); 667 } 668 669 public void mouseClicked(MouseEvent e) { 670 requestFocusInWindow(); 671 Plotter plotter = getPlotter(e); 672 673 if (plotter != null && plotter != plotterChoice.getSelectedItem()) { 674 plotterChoice.setSelectedItem(plotter); 675 repaint(); 676 } 677 } 678 679 public String getToolTipText(MouseEvent e) { 680 Plotter plotter = getPlotter(e); 681 682 return (plotter != null) ? plotter.toString() : null; 683 } 684 685 private Plotter getPlotter(MouseEvent e) { 686 Point p = e.getPoint(); 687 Plotter plotter = null; 688 689 if (heapRect.contains(p)) { 690 plotter = heapPlotter; 691 } else if (nonHeapRect.contains(p)) { 692 plotter = nonHeapPlotter; 693 } else { 694 for (PoolPlotter poolPlotter : poolPlotters) { 695 if (getBarRect(poolPlotter).contains(p)) { 696 plotter = poolPlotter; 697 break; 698 } 699 } 700 } 701 return plotter; 702 } 703 704 public void mousePressed(MouseEvent e) {} 705 public void mouseReleased(MouseEvent e) {} 706 public void mouseEntered(MouseEvent e) {} 707 public void mouseExited(MouseEvent e) {} 708 709 710 public AccessibleContext getAccessibleContext() { 711 if (accessibleContext == null) { 712 accessibleContext = new AccessiblePoolChart(); 713 } 714 return accessibleContext; 715 } 716 717 protected class AccessiblePoolChart extends AccessibleJPanel { 718 public String getAccessibleName() { 719 String name = Messages.MEMORY_TAB_POOL_CHART_ACCESSIBLE_NAME; 720 721 String keyValueList = ""; 722 for (PoolPlotter poolPlotter : poolPlotters) { 723 String value = (poolPlotter.value * 100 / poolPlotter.max) + "%"; 724 // Assume format string ends with newline 725 keyValueList += 726 Resources.format(Messages.PLOTTER_ACCESSIBLE_NAME_KEY_AND_VALUE, 727 poolPlotter.toString(), value); 728 if (poolPlotter.threshold > 0L) { 729 String threshold = 730 (poolPlotter.threshold * 100 / poolPlotter.max) + "%"; 731 if (poolPlotter.value > poolPlotter.threshold) { 732 keyValueList += 733 Resources.format(Messages.MEMORY_TAB_POOL_CHART_ABOVE_THRESHOLD, 734 threshold); 735 } else { 736 keyValueList += 737 Resources.format(Messages.MEMORY_TAB_POOL_CHART_BELOW_THRESHOLD, 738 threshold); 739 } 740 } 741 } 742 743 return name + "\n" + keyValueList + "."; 744 } 745 } 746 } 747 748 749 OverviewPanel[] getOverviewPanels() { 750 if (overviewPanel == null) { 751 overviewPanel = new MemoryOverviewPanel(); 752 } 753 return new OverviewPanel[] { overviewPanel }; 754 } 755 756 private static class MemoryOverviewPanel extends OverviewPanel { 757 MemoryOverviewPanel() { 758 super(Messages.HEAP_MEMORY_USAGE, usedKey, Messages.USED, Plotter.Unit.BYTES); 759 } 760 761 private void updateMemoryInfo(long used, long committed, long max) { 762 getInfoLabel().setText(Resources.format(Messages.MEMORY_TAB_INFO_LABEL_FORMAT, 763 formatBytes(used, true), 764 formatBytes(committed, true), 765 formatBytes(max, true))); 766 } 767 } 768 }