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