1 /* 2 * Copyright (c) 2004, 2013, 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.beans.*; 31 import java.io.*; 32 import java.net.*; 33 import java.util.*; 34 import java.util.List; 35 36 import javax.swing.*; 37 import javax.swing.border.*; 38 import javax.swing.event.*; 39 import javax.swing.plaf.*; 40 import javax.security.auth.login.FailedLoginException; 41 import javax.net.ssl.SSLHandshakeException; 42 43 import com.sun.tools.jconsole.JConsolePlugin; 44 45 import sun.net.util.IPAddressUtil; 46 47 import static sun.tools.jconsole.Utilities.*; 48 49 @SuppressWarnings("serial") 50 public class JConsole extends JFrame 51 implements ActionListener, InternalFrameListener { 52 53 static /*final*/ boolean IS_GTK; 54 static /*final*/ boolean IS_WIN; 55 56 static { 57 // Apply the system L&F if it is GTK or Windows, and 58 // the L&F is not specified using a system property. 59 if (System.getProperty("swing.defaultlaf") == null) { 60 String systemLaF = UIManager.getSystemLookAndFeelClassName(); 61 if (systemLaF.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") || 62 systemLaF.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) { 63 64 try { 65 UIManager.setLookAndFeel(systemLaF); 66 } catch (Exception e) { 67 System.err.println(Resources.format(Messages.JCONSOLE_COLON_, e.getMessage())); 68 } 69 } 70 } 71 72 updateLafValues(); 73 } 74 75 76 static void updateLafValues() { 77 String lafName = UIManager.getLookAndFeel().getClass().getName(); 78 IS_GTK = lafName.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); 79 IS_WIN = lafName.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 80 81 //BorderedComponent.updateLafValues(); 82 } 83 84 85 private final static String title = 86 Messages.JAVA_MONITORING___MANAGEMENT_CONSOLE; 87 public final static String ROOT_URL = 88 "service:jmx:"; 89 90 private static int updateInterval = 4000; 91 private static String pluginPath = ""; 92 93 private JMenuBar menuBar; 94 private JMenuItem hotspotMI, connectMI, exitMI; 95 private WindowMenu windowMenu; 96 private JMenuItem tileMI, cascadeMI, minimizeAllMI, restoreAllMI; 97 private JMenuItem userGuideMI, aboutMI; 98 99 private JButton connectButton; 100 private JDesktopPane desktop; 101 private ConnectDialog connectDialog; 102 private CreateMBeanDialog createDialog; 103 104 private ArrayList<VMInternalFrame> windows = 105 new ArrayList<VMInternalFrame>(); 106 107 private int frameLoc = 5; 108 static boolean debug; 109 110 public JConsole(boolean hotspot) { 111 super(title); 112 113 setRootPane(new FixedJRootPane()); 114 setAccessibleDescription(this, 115 Messages.JCONSOLE_ACCESSIBLE_DESCRIPTION); 116 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 117 118 menuBar = new JMenuBar(); 119 setJMenuBar(menuBar); 120 121 // TODO: Use Actions ! 122 123 JMenu connectionMenu = new JMenu(Messages.CONNECTION); 124 connectionMenu.setMnemonic(Resources.getMnemonicInt(Messages.CONNECTION)); 125 menuBar.add(connectionMenu); 126 if(hotspot) { 127 hotspotMI = new JMenuItem(Messages.HOTSPOT_MBEANS_ELLIPSIS); 128 hotspotMI.setMnemonic(Resources.getMnemonicInt(Messages.HOTSPOT_MBEANS_ELLIPSIS)); 129 hotspotMI.setAccelerator(KeyStroke. 130 getKeyStroke(KeyEvent.VK_H, 131 InputEvent.CTRL_DOWN_MASK)); 132 hotspotMI.addActionListener(this); 133 connectionMenu.add(hotspotMI); 134 135 connectionMenu.addSeparator(); 136 } 137 138 connectMI = new JMenuItem(Messages.NEW_CONNECTION_ELLIPSIS); 139 connectMI.setMnemonic(Resources.getMnemonicInt(Messages.NEW_CONNECTION_ELLIPSIS)); 140 connectMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 141 InputEvent.CTRL_DOWN_MASK)); 142 connectMI.addActionListener(this); 143 connectionMenu.add(connectMI); 144 145 connectionMenu.addSeparator(); 146 147 exitMI = new JMenuItem(Messages.EXIT); 148 exitMI.setMnemonic(Resources.getMnemonicInt(Messages.EXIT)); 149 exitMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 150 InputEvent.ALT_DOWN_MASK)); 151 exitMI.addActionListener(this); 152 connectionMenu.add(exitMI); 153 154 155 JMenu helpMenu = new JMenu(Messages.HELP_MENU_TITLE); 156 helpMenu.setMnemonic(Resources.getMnemonicInt(Messages.HELP_MENU_TITLE)); 157 menuBar.add(helpMenu); 158 159 if (AboutDialog.isBrowseSupported()) { 160 userGuideMI = new JMenuItem(Messages.HELP_MENU_USER_GUIDE_TITLE); 161 userGuideMI.setMnemonic(Resources.getMnemonicInt(Messages.HELP_MENU_USER_GUIDE_TITLE)); 162 userGuideMI.addActionListener(this); 163 helpMenu.add(userGuideMI); 164 helpMenu.addSeparator(); 165 } 166 aboutMI = new JMenuItem(Messages.HELP_MENU_ABOUT_TITLE); 167 aboutMI.setMnemonic(Resources.getMnemonicInt(Messages.HELP_MENU_ABOUT_TITLE)); 168 aboutMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); 169 aboutMI.addActionListener(this); 170 helpMenu.add(aboutMI); 171 } 172 173 public JDesktopPane getDesktopPane() { 174 return desktop; 175 } 176 177 public List<VMInternalFrame> getInternalFrames() { 178 return windows; 179 } 180 181 private void createMDI() { 182 // Restore title - we now show connection name on internal frames 183 setTitle(title); 184 185 Container cp = getContentPane(); 186 Component oldCenter = 187 ((BorderLayout)cp.getLayout()). 188 getLayoutComponent(BorderLayout.CENTER); 189 190 windowMenu = new WindowMenu(Messages.WINDOW); 191 windowMenu.setMnemonic(Resources.getMnemonicInt(Messages.WINDOW)); 192 // Add Window menu before Help menu 193 menuBar.add(windowMenu, menuBar.getComponentCount() - 1); 194 195 desktop = new JDesktopPane(); 196 desktop.setBackground(new Color(235, 245, 255)); 197 198 cp.add(desktop, BorderLayout.CENTER); 199 200 if (oldCenter instanceof VMPanel) { 201 addFrame((VMPanel)oldCenter); 202 } 203 } 204 205 private class WindowMenu extends JMenu { 206 VMInternalFrame[] windowMenuWindows = new VMInternalFrame[0]; 207 int separatorPosition; 208 209 // The width value of viewR is used to truncate long menu items. 210 // The rest are placeholders and are ignored for this purpose. 211 Rectangle viewR = new Rectangle(0, 0, 400, 20); 212 Rectangle textR = new Rectangle(0, 0, 0, 0); 213 Rectangle iconR = new Rectangle(0, 0, 0, 0); 214 215 WindowMenu(String text) { 216 super(text); 217 218 cascadeMI = new JMenuItem(Messages.CASCADE); 219 cascadeMI.setMnemonic(Resources.getMnemonicInt(Messages.CASCADE)); 220 cascadeMI.addActionListener(JConsole.this); 221 add(cascadeMI); 222 223 tileMI = new JMenuItem(Messages.TILE); 224 tileMI.setMnemonic(Resources.getMnemonicInt(Messages.TILE)); 225 tileMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 226 InputEvent.CTRL_DOWN_MASK)); 227 tileMI.addActionListener(JConsole.this); 228 add(tileMI); 229 230 minimizeAllMI = new JMenuItem(Messages.MINIMIZE_ALL); 231 minimizeAllMI.setMnemonic(Resources.getMnemonicInt(Messages.MINIMIZE_ALL)); 232 minimizeAllMI.addActionListener(JConsole.this); 233 add(minimizeAllMI); 234 235 restoreAllMI = new JMenuItem(Messages.RESTORE_ALL); 236 restoreAllMI.setMnemonic(Resources.getMnemonicInt(Messages.RESTORE_ALL)); 237 restoreAllMI.addActionListener(JConsole.this); 238 add(restoreAllMI); 239 240 separatorPosition = getMenuComponentCount(); 241 } 242 243 private void add(VMInternalFrame vmIF) { 244 if (separatorPosition == getMenuComponentCount()) { 245 addSeparator(); 246 } 247 248 int index = -1; 249 int position = separatorPosition + 1; 250 int n = windowMenuWindows.length; 251 252 for (int i = 0; i < n; i++) { 253 if (windowMenuWindows[i] != null) { 254 // Slot is in use, try next 255 position++; 256 } else { 257 // Found a free slot 258 index = i; 259 break; 260 } 261 } 262 263 if (index == -1) { 264 // Create a slot at the end 265 VMInternalFrame[] newArray = new VMInternalFrame[n + 1]; 266 System.arraycopy(windowMenuWindows, 0, newArray, 0, n); 267 windowMenuWindows = newArray; 268 index = n; 269 } 270 271 windowMenuWindows[index] = vmIF; 272 273 String indexString = "" + (index+1); 274 String vmName = vmIF.getVMPanel().getDisplayName(); 275 // Maybe truncate menu item string and end with "..." 276 String text = 277 SwingUtilities.layoutCompoundLabel(this, 278 getGraphics().getFontMetrics(getFont()), 279 indexString + " " + vmName, 280 null, 0, 0, 0, 0, 281 viewR, iconR, textR, 0); 282 JMenuItem mi = new JMenuItem(text); 283 if (text.endsWith("...")) { 284 mi.setToolTipText(vmName); 285 } 286 287 // Set mnemonic using last digit of number 288 int nDigits = indexString.length(); 289 mi.setMnemonic(indexString.charAt(nDigits-1)); 290 mi.setDisplayedMnemonicIndex(nDigits-1); 291 292 mi.putClientProperty("JConsole.vmIF", vmIF); 293 mi.addActionListener(JConsole.this); 294 vmIF.putClientProperty("JConsole.menuItem", mi); 295 add(mi, position); 296 } 297 298 private void remove(VMInternalFrame vmIF) { 299 for (int i = 0; i < windowMenuWindows.length; i++) { 300 if (windowMenuWindows[i] == vmIF) { 301 windowMenuWindows[i] = null; 302 } 303 } 304 JMenuItem mi = (JMenuItem)vmIF.getClientProperty("JConsole.menuItem"); 305 remove(mi); 306 mi.putClientProperty("JConsole.vmIF", null); 307 vmIF.putClientProperty("JConsole.menuItem", null); 308 309 if (separatorPosition == getMenuComponentCount() - 1) { 310 remove(getMenuComponent(getMenuComponentCount() - 1)); 311 } 312 } 313 } 314 315 public void actionPerformed(ActionEvent ev) { 316 Object src = ev.getSource(); 317 if (src == hotspotMI) { 318 showCreateMBeanDialog(); 319 } 320 321 if (src == connectButton || src == connectMI) { 322 VMPanel vmPanel = null; 323 JInternalFrame vmIF = desktop.getSelectedFrame(); 324 if (vmIF instanceof VMInternalFrame) { 325 vmPanel = ((VMInternalFrame)vmIF).getVMPanel(); 326 } 327 String hostName = ""; 328 String url = ""; 329 if (vmPanel != null) { 330 hostName = vmPanel.getHostName(); 331 if(vmPanel.getUrl() != null) 332 url = vmPanel.getUrl(); 333 } 334 showConnectDialog(url, hostName, 0, null, null, null); 335 } else if (src == tileMI) { 336 tileWindows(); 337 } else if (src == cascadeMI) { 338 cascadeWindows(); 339 } else if (src == minimizeAllMI) { 340 for (VMInternalFrame vmIF : windows) { 341 try { 342 vmIF.setIcon(true); 343 } catch (PropertyVetoException ex) { 344 // Ignore 345 } 346 } 347 } else if (src == restoreAllMI) { 348 for (VMInternalFrame vmIF : windows) { 349 try { 350 vmIF.setIcon(false); 351 } catch (PropertyVetoException ex) { 352 // Ignore 353 } 354 } 355 } else if (src == exitMI) { 356 System.exit(0); 357 } else if (src == userGuideMI) { 358 AboutDialog.browseUserGuide(this); 359 } else if (src == aboutMI) { 360 AboutDialog.showAboutDialog(this); 361 } else if (src instanceof JMenuItem) { 362 JMenuItem mi = (JMenuItem)src; 363 VMInternalFrame vmIF = (VMInternalFrame)mi. 364 getClientProperty("JConsole.vmIF"); 365 if (vmIF != null) { 366 try { 367 vmIF.setIcon(false); 368 vmIF.setSelected(true); 369 } catch (PropertyVetoException ex) { 370 // Ignore 371 } 372 vmIF.moveToFront(); 373 } 374 } 375 } 376 377 378 public void tileWindows() { 379 int w = -1; 380 int h = -1; 381 int n = 0; 382 for (VMInternalFrame vmIF : windows) { 383 if (!vmIF.isIcon()) { 384 n++; 385 if (w == -1) { 386 try { 387 vmIF.setMaximum(true); 388 w = vmIF.getWidth(); 389 h = vmIF.getHeight(); 390 } catch (PropertyVetoException ex) { 391 // Ignore 392 } 393 } 394 } 395 } 396 if (n > 0 && w > 0 && h > 0) { 397 int rows = (int)Math.ceil(Math.sqrt(n)); 398 int cols = n / rows; 399 if (rows * cols < n) cols++; 400 int x = 0; 401 int y = 0; 402 w /= cols; 403 h /= rows; 404 int col = 0; 405 for (VMInternalFrame vmIF : windows) { 406 if (!vmIF.isIcon()) { 407 try { 408 vmIF.setMaximum(n==1); 409 } catch (PropertyVetoException ex) { 410 // Ignore 411 } 412 if (n > 1) { 413 vmIF.setBounds(x, y, w, h); 414 } 415 if (col < cols-1) { 416 col++; 417 x += w; 418 } else { 419 col = 0; 420 x = 0; 421 y += h; 422 } 423 } 424 } 425 } 426 } 427 428 public void cascadeWindows() { 429 int n = 0; 430 int w = -1; 431 int h = -1; 432 for (VMInternalFrame vmIF : windows) { 433 if (!vmIF.isIcon()) { 434 try { 435 vmIF.setMaximum(false); 436 } catch (PropertyVetoException ex) { 437 // Ignore 438 } 439 n++; 440 vmIF.pack(); 441 if (w == -1) { 442 try { 443 w = vmIF.getWidth(); 444 h = vmIF.getHeight(); 445 vmIF.setMaximum(true); 446 w = vmIF.getWidth() - w; 447 h = vmIF.getHeight() - h; 448 vmIF.pack(); 449 } catch (PropertyVetoException ex) { 450 // Ignore 451 } 452 } 453 } 454 } 455 int x = 0; 456 int y = 0; 457 int dX = (n > 1) ? (w / (n - 1)) : 0; 458 int dY = (n > 1) ? (h / (n - 1)) : 0; 459 for (VMInternalFrame vmIF : windows) { 460 if (!vmIF.isIcon()) { 461 vmIF.setLocation(x, y); 462 vmIF.moveToFront(); 463 x += dX; 464 y += dY; 465 } 466 } 467 } 468 469 // Call on EDT 470 void addHost(String hostName, int port, 471 String userName, String password) { 472 addHost(hostName, port, userName, password, false); 473 } 474 475 // Call on EDT 476 void addVmid(LocalVirtualMachine lvm) { 477 addVmid(lvm, false); 478 } 479 480 // Call on EDT 481 void addVmid(final LocalVirtualMachine lvm, final boolean tile) { 482 new Thread("JConsole.addVmid") { 483 public void run() { 484 try { 485 addProxyClient(ProxyClient.getProxyClient(lvm), tile); 486 } catch (final SecurityException ex) { 487 failed(ex, null, null, null); 488 } catch (final IOException ex) { 489 failed(ex, null, null, null); 490 } 491 } 492 }.start(); 493 } 494 495 // Call on EDT 496 void addUrl(final String url, 497 final String userName, 498 final String password, 499 final boolean tile) { 500 new Thread("JConsole.addUrl") { 501 public void run() { 502 try { 503 addProxyClient(ProxyClient.getProxyClient(url, userName, password), 504 tile); 505 } catch (final MalformedURLException ex) { 506 failed(ex, url, userName, password); 507 } catch (final SecurityException ex) { 508 failed(ex, url, userName, password); 509 } catch (final IOException ex) { 510 failed(ex, url, userName, password); 511 } 512 } 513 }.start(); 514 } 515 516 517 // Call on EDT 518 void addHost(final String hostName, final int port, 519 final String userName, final String password, 520 final boolean tile) { 521 new Thread("JConsole.addHost") { 522 public void run() { 523 try { 524 addProxyClient(ProxyClient.getProxyClient(hostName, port, 525 userName, password), 526 tile); 527 } catch (final IOException ex) { 528 dbgStackTrace(ex); 529 SwingUtilities.invokeLater(new Runnable() { 530 public void run() { 531 showConnectDialog(null, hostName, port, 532 userName, password, errorMessage(ex)); 533 } 534 }); 535 } 536 } 537 }.start(); 538 } 539 540 541 // Call on worker thread 542 void addProxyClient(final ProxyClient proxyClient, final boolean tile) { 543 SwingUtilities.invokeLater(new Runnable() { 544 public void run() { 545 VMPanel vmPanel = new VMPanel(proxyClient, updateInterval); 546 addFrame(vmPanel); 547 548 if (tile) { 549 SwingUtilities.invokeLater(new Runnable() { 550 public void run() { 551 tileWindows(); 552 } 553 }); 554 } 555 vmPanel.connect(); 556 } 557 }); 558 } 559 560 561 // Call on worker thread 562 private void failed(final Exception ex, 563 final String url, 564 final String userName, 565 final String password) { 566 SwingUtilities.invokeLater(new Runnable() { 567 public void run() { 568 dbgStackTrace(ex); 569 showConnectDialog(url, 570 null, 571 -1, 572 userName, 573 password, 574 errorMessage(ex)); 575 } 576 }); 577 } 578 579 580 private VMInternalFrame addFrame(VMPanel vmPanel) { 581 final VMInternalFrame vmIF = new VMInternalFrame(vmPanel); 582 583 for (VMInternalFrame f : windows) { 584 try { 585 f.setMaximum(false); 586 } catch (PropertyVetoException ex) { 587 // Ignore 588 } 589 } 590 desktop.add(vmIF); 591 592 vmIF.setLocation(frameLoc, frameLoc); 593 frameLoc += 30; 594 vmIF.setVisible(true); 595 windows.add(vmIF); 596 if (windows.size() == 1) { 597 try { 598 vmIF.setMaximum(true); 599 } catch (PropertyVetoException ex) { 600 // Ignore 601 } 602 } 603 vmIF.addInternalFrameListener(this); 604 windowMenu.add(vmIF); 605 606 return vmIF; 607 } 608 609 private void showConnectDialog(String url, 610 String hostName, 611 int port, 612 String userName, 613 String password, 614 String msg) { 615 if (connectDialog == null) { 616 connectDialog = new ConnectDialog(this); 617 } 618 connectDialog.setConnectionParameters(url, 619 hostName, 620 port, 621 userName, 622 password, 623 msg); 624 625 connectDialog.refresh(); 626 connectDialog.setVisible(true); 627 try { 628 // Bring to front of other dialogs 629 connectDialog.setSelected(true); 630 } catch (PropertyVetoException e) { 631 } 632 } 633 634 private void showCreateMBeanDialog() { 635 if (createDialog == null) { 636 createDialog = new CreateMBeanDialog(this); 637 } 638 createDialog.setVisible(true); 639 try { 640 // Bring to front of other dialogs 641 createDialog.setSelected(true); 642 } catch (PropertyVetoException e) { 643 } 644 } 645 646 private void removeVMInternalFrame(VMInternalFrame vmIF) { 647 windowMenu.remove(vmIF); 648 desktop.remove(vmIF); 649 desktop.repaint(); 650 vmIF.getVMPanel().cleanUp(); 651 vmIF.dispose(); 652 } 653 654 private boolean isProxyClientUsed(ProxyClient client) { 655 for(VMInternalFrame frame : windows) { 656 ProxyClient cli = frame.getVMPanel().getProxyClient(false); 657 if(client == cli) 658 return true; 659 } 660 return false; 661 } 662 663 static boolean isValidRemoteString(String txt) { 664 boolean valid = false; 665 if (txt != null) { 666 txt = txt.trim(); 667 if (txt.startsWith(ROOT_URL)) { 668 if (txt.length() > ROOT_URL.length()) { 669 valid = true; 670 } 671 } else { 672 //--------------------------------------- 673 // Supported host and port combinations: 674 // hostname:port 675 // IPv4Address:port 676 // [IPv6Address]:port 677 //--------------------------------------- 678 679 // Is literal IPv6 address? 680 // 681 if (txt.startsWith("[")) { 682 int index = txt.indexOf("]:"); 683 if (index != -1) { 684 // Extract literal IPv6 address 685 // 686 String address = txt.substring(1, index); 687 if (IPAddressUtil.isIPv6LiteralAddress(address)) { 688 // Extract port 689 // 690 try { 691 String portStr = txt.substring(index + 2); 692 int port = Integer.parseInt(portStr); 693 if (port >= 0 && port <= 0xFFFF) { 694 valid = true; 695 } 696 } catch (NumberFormatException ex) { 697 valid = false; 698 } 699 } 700 } 701 } else { 702 String[] s = txt.split(":"); 703 if (s.length == 2) { 704 try { 705 int port = Integer.parseInt(s[1]); 706 if (port >= 0 && port <= 0xFFFF) { 707 valid = true; 708 } 709 } catch (NumberFormatException ex) { 710 valid = false; 711 } 712 } 713 } 714 } 715 } 716 return valid; 717 } 718 719 private String errorMessage(Exception ex) { 720 String msg = Messages.CONNECTION_FAILED; 721 if (ex instanceof IOException || ex instanceof SecurityException) { 722 Throwable cause = null; 723 Throwable c = ex.getCause(); 724 while (c != null) { 725 cause = c; 726 c = c.getCause(); 727 } 728 if (cause instanceof ConnectException) { 729 return msg + ": " + cause.getMessage(); 730 } else if (cause instanceof UnknownHostException) { 731 return Resources.format(Messages.UNKNOWN_HOST, cause.getMessage()); 732 } else if (cause instanceof NoRouteToHostException) { 733 return msg + ": " + cause.getMessage(); 734 } else if (cause instanceof FailedLoginException) { 735 return msg + ": " + cause.getMessage(); 736 } else if (cause instanceof SSLHandshakeException) { 737 return msg + ": "+ cause.getMessage(); 738 } 739 } else if (ex instanceof MalformedURLException) { 740 return Resources.format(Messages.INVALID_URL, ex.getMessage()); 741 } 742 return msg + ": " + ex.getMessage(); 743 } 744 745 746 // InternalFrameListener interface 747 748 public void internalFrameClosing(InternalFrameEvent e) { 749 VMInternalFrame vmIF = (VMInternalFrame)e.getInternalFrame(); 750 removeVMInternalFrame(vmIF); 751 windows.remove(vmIF); 752 ProxyClient client = vmIF.getVMPanel().getProxyClient(false); 753 if(!isProxyClientUsed(client)) 754 client.markAsDead(); 755 if (windows.size() == 0) { 756 showConnectDialog("", "", 0, null, null, null); 757 } 758 } 759 760 public void internalFrameOpened(InternalFrameEvent e) {} 761 public void internalFrameClosed(InternalFrameEvent e) {} 762 public void internalFrameIconified(InternalFrameEvent e) {} 763 public void internalFrameDeiconified(InternalFrameEvent e) {} 764 public void internalFrameActivated(InternalFrameEvent e) {} 765 public void internalFrameDeactivated(InternalFrameEvent e) {} 766 767 768 private static void usage() { 769 System.err.println(Resources.format(Messages.ZZ_USAGE_TEXT, "jconsole")); 770 } 771 772 private static void mainInit(final List<String> urls, 773 final List<String> hostNames, 774 final List<Integer> ports, 775 final List<LocalVirtualMachine> vmids, 776 final ProxyClient proxyClient, 777 final boolean noTile, 778 final boolean hotspot) { 779 780 781 // Always create Swing GUI on the Event Dispatching Thread 782 SwingUtilities.invokeLater(new Runnable() { 783 public void run() { 784 JConsole jConsole = new JConsole(hotspot); 785 786 // Center the window on screen, taking into account screen 787 // size and insets. 788 Toolkit toolkit = Toolkit.getDefaultToolkit(); 789 GraphicsConfiguration gc = jConsole.getGraphicsConfiguration(); 790 Dimension scrSize = toolkit.getScreenSize(); 791 Insets scrInsets = toolkit.getScreenInsets(gc); 792 Rectangle scrBounds = 793 new Rectangle(scrInsets.left, scrInsets.top, 794 scrSize.width - scrInsets.left - scrInsets.right, 795 scrSize.height - scrInsets.top - scrInsets.bottom); 796 int w = Math.min(900, scrBounds.width); 797 int h = Math.min(750, scrBounds.height); 798 jConsole.setBounds(scrBounds.x + (scrBounds.width - w) / 2, 799 scrBounds.y + (scrBounds.height - h) / 2, 800 w, h); 801 802 jConsole.setVisible(true); 803 jConsole.createMDI(); 804 805 for (int i = 0; i < hostNames.size(); i++) { 806 jConsole.addHost(hostNames.get(i), ports.get(i), 807 null, null, 808 (i == hostNames.size() - 1) ? 809 !noTile : false); 810 } 811 812 for (int i = 0; i < urls.size(); i++) { 813 jConsole.addUrl(urls.get(i), 814 null, 815 null, 816 (i == urls.size() - 1) ? 817 !noTile : false); 818 } 819 820 for (int i = 0; i < vmids.size(); i++) { 821 jConsole.addVmid(vmids.get(i), 822 (i == vmids.size() - 1) ? 823 !noTile : false); 824 } 825 826 if (vmids.size() == 0 && 827 hostNames.size() == 0 && 828 urls.size() == 0) { 829 jConsole.showConnectDialog(null, 830 null, 831 0, 832 null, 833 null, 834 null); 835 } 836 } 837 }); 838 } 839 840 public static void main(String[] args) { 841 boolean noTile = false, hotspot = false; 842 int argIndex = 0; 843 ProxyClient proxyClient = null; 844 845 if (System.getProperty("jconsole.showOutputViewer") != null) { 846 OutputViewer.init(); 847 } 848 849 while (args.length - argIndex > 0 && args[argIndex].startsWith("-")) { 850 String arg = args[argIndex++]; 851 if (arg.equals("-h") || 852 arg.equals("-help") || 853 arg.equals("-?")) { 854 855 usage(); 856 return; 857 } else if (arg.startsWith("-interval=")) { 858 try { 859 updateInterval = Integer.parseInt(arg.substring(10)) * 860 1000; 861 if (updateInterval <= 0) { 862 usage(); 863 return; 864 } 865 } catch (NumberFormatException ex) { 866 usage(); 867 return; 868 } 869 } else if (arg.equals("-pluginpath")) { 870 if (argIndex < args.length && !args[argIndex].startsWith("-")) { 871 pluginPath = args[argIndex++]; 872 } else { 873 // Invalid argument 874 usage(); 875 return; 876 } 877 } else if (arg.equals("-notile")) { 878 noTile = true; 879 } else if (arg.equals("-version")) { 880 Version.print(System.err); 881 return; 882 } else if (arg.equals("-debug")) { 883 debug = true; 884 } else if (arg.equals("-fullversion")) { 885 Version.printFullVersion(System.err); 886 return; 887 } else { 888 // Unknown switch 889 usage(); 890 return; 891 } 892 } 893 894 if (System.getProperty("jconsole.showUnsupported") != null) { 895 hotspot = true; 896 } 897 898 List<String> urls = new ArrayList<String>(); 899 List<String> hostNames = new ArrayList<String>(); 900 List<Integer> ports = new ArrayList<Integer>(); 901 List<LocalVirtualMachine> vms = new ArrayList<LocalVirtualMachine>(); 902 903 for (int i = argIndex; i < args.length; i++) { 904 String arg = args[i]; 905 if (isValidRemoteString(arg)) { 906 if (arg.startsWith(ROOT_URL)) { 907 urls.add(arg); 908 } else if (arg.matches(".*:[0-9]*")) { 909 int p = arg.lastIndexOf(':'); 910 hostNames.add(arg.substring(0, p)); 911 try { 912 ports.add(Integer.parseInt(arg.substring(p+1))); 913 } catch (NumberFormatException ex) { 914 usage(); 915 return; 916 } 917 } 918 } else { 919 if (!isLocalAttachAvailable()) { 920 System.err.println("Local process monitoring is not supported"); 921 return; 922 } 923 try { 924 int vmid = Integer.parseInt(arg); 925 LocalVirtualMachine lvm = 926 LocalVirtualMachine.getLocalVirtualMachine(vmid); 927 if (lvm == null) { 928 System.err.println("Invalid process id:" + vmid); 929 return; 930 } 931 vms.add(lvm); 932 } catch (NumberFormatException ex) { 933 usage(); 934 return; 935 } 936 } 937 } 938 939 mainInit(urls, hostNames, ports, vms, proxyClient, noTile, hotspot); 940 } 941 942 public static boolean isDebug() { 943 return debug; 944 } 945 946 private static void dbgStackTrace(Exception ex) { 947 if (debug) { 948 ex.printStackTrace(); 949 } 950 } 951 952 private static final boolean localAttachmentSupported; 953 static { 954 boolean supported; 955 try { 956 Class.forName("com.sun.tools.attach.VirtualMachine"); 957 Class.forName("sun.management.ConnectorAddressLink"); 958 supported = true; 959 } catch (NoClassDefFoundError x) { 960 supported = false; 961 } catch (ClassNotFoundException x) { 962 supported = false; 963 } 964 localAttachmentSupported = supported; 965 } 966 967 public static boolean isLocalAttachAvailable() { 968 return localAttachmentSupported; 969 } 970 971 972 private static ServiceLoader<JConsolePlugin> pluginService = null; 973 974 // Return a list of newly instantiated JConsolePlugin objects 975 static synchronized List<JConsolePlugin> getPlugins() { 976 if (pluginService == null) { 977 // First time loading and initializing the plugins 978 initPluginService(pluginPath); 979 } else { 980 // reload the plugin so that new instances will be created 981 pluginService.reload(); 982 } 983 984 List<JConsolePlugin> plugins = new ArrayList<JConsolePlugin>(); 985 for (JConsolePlugin p : pluginService) { 986 plugins.add(p); 987 } 988 return plugins; 989 } 990 991 private static void initPluginService(String pluginPath) { 992 if (pluginPath.length() > 0) { 993 try { 994 ClassLoader pluginCL = new URLClassLoader(pathToURLs(pluginPath)); 995 ServiceLoader<JConsolePlugin> plugins = 996 ServiceLoader.load(JConsolePlugin.class, pluginCL); 997 // validate all plugins 998 for (JConsolePlugin p : plugins) { 999 if (isDebug()) { 1000 System.out.println("Plugin " + p.getClass() + " loaded."); 1001 } 1002 } 1003 pluginService = plugins; 1004 } catch (ServiceConfigurationError e) { 1005 // Error occurs during initialization of plugin 1006 System.out.println(Resources.format(Messages.FAIL_TO_LOAD_PLUGIN, 1007 e.getMessage())); 1008 } catch (MalformedURLException e) { 1009 if (JConsole.isDebug()) { 1010 e.printStackTrace(); 1011 } 1012 System.out.println(Resources.format(Messages.INVALID_PLUGIN_PATH, 1013 e.getMessage())); 1014 } 1015 } 1016 1017 if (pluginService == null) { 1018 initEmptyPlugin(); 1019 } 1020 } 1021 1022 private static void initEmptyPlugin() { 1023 ClassLoader pluginCL = new URLClassLoader(new URL[0]); 1024 pluginService = ServiceLoader.load(JConsolePlugin.class, pluginCL); 1025 } 1026 1027 /** 1028 * Utility method for converting a search path string to an array 1029 * of directory and JAR file URLs. 1030 * 1031 * @param path the search path string 1032 * @return the resulting array of directory and JAR file URLs 1033 */ 1034 private static URL[] pathToURLs(String path) throws MalformedURLException { 1035 String[] names = path.split(File.pathSeparator); 1036 URL[] urls = new URL[names.length]; 1037 int count = 0; 1038 for (String f : names) { 1039 URL url = fileToURL(new File(f)); 1040 urls[count++] = url; 1041 } 1042 return urls; 1043 } 1044 1045 /** 1046 * Returns the directory or JAR file URL corresponding to the specified 1047 * local file name. 1048 * 1049 * @param file the File object 1050 * @return the resulting directory or JAR file URL, or null if unknown 1051 */ 1052 private static URL fileToURL(File file) throws MalformedURLException { 1053 String name; 1054 try { 1055 name = file.getCanonicalPath(); 1056 } catch (IOException e) { 1057 name = file.getAbsolutePath(); 1058 } 1059 name = name.replace(File.separatorChar, '/'); 1060 if (!name.startsWith("/")) { 1061 name = "/" + name; 1062 } 1063 // If the file does not exist, then assume that it's a directory 1064 if (!file.isFile()) { 1065 name = name + "/"; 1066 } 1067 return new URL("file", "", name); 1068 } 1069 1070 1071 private static class FixedJRootPane extends JRootPane { 1072 public void updateUI() { 1073 updateLafValues(); 1074 super.updateUI(); 1075 } 1076 1077 /** 1078 * The revalidate method seems to be the only one that gets 1079 * called whenever there is a change of L&F or change of theme 1080 * in Windows L&F and GTK L&F. 1081 */ 1082 @Override 1083 public void revalidate() { 1084 // Workaround for Swing bug where the titledborder in both 1085 // GTK and Windows L&F's use calculated colors instead of 1086 // the highlight/shadow colors from the theme. 1087 // 1088 // Putting null removes any previous override and causes a 1089 // fallback to the current L&F's value. 1090 UIManager.put("TitledBorder.border", null); 1091 Border border = UIManager.getBorder("TitledBorder.border"); 1092 if (border instanceof BorderUIResource.EtchedBorderUIResource) { 1093 Color highlight = UIManager.getColor("ToolBar.highlight"); 1094 Color shadow = UIManager.getColor("ToolBar.shadow"); 1095 border = new BorderUIResource.EtchedBorderUIResource(highlight, 1096 shadow); 1097 UIManager.put("TitledBorder.border", border); 1098 } 1099 1100 if (IS_GTK) { 1101 // Workaround for Swing bug where the titledborder in 1102 // GTK L&F use hardcoded color and font for the title 1103 // instead of getting them from the theme. 1104 UIManager.put("TitledBorder.titleColor", 1105 UIManager.getColor("Label.foreground")); 1106 UIManager.put("TitledBorder.font", 1107 UIManager.getFont("Label.font")); 1108 } 1109 super.revalidate(); 1110 } 1111 } 1112 }