1 /* 2 * Copyright (c) 2004, 2006, 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.lang.reflect.InvocationTargetException; 33 import java.net.*; 34 import java.util.*; 35 import java.util.List; 36 37 import javax.swing.*; 38 import javax.swing.border.*; 39 import javax.swing.event.*; 40 import javax.swing.plaf.*; 41 import javax.management.remote.JMXServiceURL; 42 import javax.management.remote.JMXConnector; 43 import javax.security.auth.login.FailedLoginException; 44 import javax.net.ssl.SSLHandshakeException; 45 46 import com.sun.tools.jconsole.JConsolePlugin; 47 48 import sun.net.util.IPAddressUtil; 49 50 import static sun.tools.jconsole.Resources.*; 51 import static sun.tools.jconsole.Utilities.*; 52 53 @SuppressWarnings("serial") 54 public class JConsole extends JFrame 55 implements ActionListener, InternalFrameListener { 56 57 static /*final*/ boolean IS_GTK; 58 static /*final*/ boolean IS_WIN; 59 60 static { 61 // Apply the system L&F if it is GTK or Windows, and 62 // the L&F is not specified using a system property. 63 if (System.getProperty("swing.defaultlaf") == null) { 64 String systemLaF = UIManager.getSystemLookAndFeelClassName(); 65 if (systemLaF.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") || 66 systemLaF.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) { 67 68 try { 69 UIManager.setLookAndFeel(systemLaF); 70 } catch (Exception e) { 71 System.err.println(Resources.getText("JConsole: ", e.getMessage())); 72 } 73 } 74 } 75 76 updateLafValues(); 77 } 78 79 80 static void updateLafValues() { 81 String lafName = UIManager.getLookAndFeel().getClass().getName(); 82 IS_GTK = lafName.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); 83 IS_WIN = lafName.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 84 85 //BorderedComponent.updateLafValues(); 86 } 87 88 89 private final static String title = 90 Resources.getText("Java Monitoring & Management Console"); 91 public final static String ROOT_URL = 92 "service:jmx:"; 93 94 private static int updateInterval = 4000; 95 private static String pluginPath = ""; 96 97 private JMenuBar menuBar; 98 private JMenuItem hotspotMI, connectMI, exitMI; 99 private WindowMenu windowMenu; 100 private JMenuItem tileMI, cascadeMI, minimizeAllMI, restoreAllMI; 101 private JMenuItem userGuideMI, aboutMI; 102 103 private JButton connectButton; 104 private JDesktopPane desktop; 105 private ConnectDialog connectDialog; 106 private CreateMBeanDialog createDialog; 107 108 private ArrayList<VMInternalFrame> windows = 109 new ArrayList<VMInternalFrame>(); 110 111 private int frameLoc = 5; 112 static boolean debug; 113 114 public JConsole(boolean hotspot) { 115 super(title); 116 117 setRootPane(new FixedJRootPane()); 118 setAccessibleDescription(this, 119 getText("JConsole.accessibleDescription")); 120 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 121 122 menuBar = new JMenuBar(); 123 setJMenuBar(menuBar); 124 125 // TODO: Use Actions ! 126 127 JMenu connectionMenu = new JMenu(getText("Connection")); 128 connectionMenu.setMnemonic(getMnemonicInt("Connection")); 129 menuBar.add(connectionMenu); 130 if(hotspot) { 131 hotspotMI = new JMenuItem(getText("Hotspot MBeans...")); 132 hotspotMI.setMnemonic(getMnemonicInt("Hotspot MBeans...")); 133 hotspotMI.setAccelerator(KeyStroke. 134 getKeyStroke(KeyEvent.VK_H, 135 InputEvent.CTRL_MASK)); 136 hotspotMI.addActionListener(this); 137 connectionMenu.add(hotspotMI); 138 139 connectionMenu.addSeparator(); 140 } 141 142 connectMI = new JMenuItem(Resources.getText("New Connection...")); 143 connectMI.setMnemonic(getMnemonicInt("New Connection...")); 144 connectMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 145 InputEvent.CTRL_MASK)); 146 connectMI.addActionListener(this); 147 connectionMenu.add(connectMI); 148 149 connectionMenu.addSeparator(); 150 151 exitMI = new JMenuItem(Resources.getText("Exit")); 152 exitMI.setMnemonic(getMnemonicInt("Exit")); 153 exitMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 154 InputEvent.ALT_MASK)); 155 exitMI.addActionListener(this); 156 connectionMenu.add(exitMI); 157 158 159 JMenu helpMenu = new JMenu(getText("HelpMenu.title")); 160 helpMenu.setMnemonic(getMnemonicInt("HelpMenu.title")); 161 menuBar.add(helpMenu); 162 163 if (AboutDialog.isBrowseSupported()) { 164 userGuideMI = new JMenuItem(getText("HelpMenu.UserGuide.title")); 165 userGuideMI.setMnemonic(getMnemonicInt("HelpMenu.UserGuide.title")); 166 userGuideMI.addActionListener(this); 167 helpMenu.add(userGuideMI); 168 helpMenu.addSeparator(); 169 } 170 aboutMI = new JMenuItem(getText("HelpMenu.About.title")); 171 aboutMI.setMnemonic(getMnemonicInt("HelpMenu.About.title")); 172 aboutMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); 173 aboutMI.addActionListener(this); 174 helpMenu.add(aboutMI); 175 } 176 177 public JDesktopPane getDesktopPane() { 178 return desktop; 179 } 180 181 public List<VMInternalFrame> getInternalFrames() { 182 return windows; 183 } 184 185 private void createMDI() { 186 // Restore title - we now show connection name on internal frames 187 setTitle(title); 188 189 Container cp = getContentPane(); 190 Component oldCenter = 191 ((BorderLayout)cp.getLayout()). 192 getLayoutComponent(BorderLayout.CENTER); 193 194 windowMenu = new WindowMenu(Resources.getText("Window")); 195 windowMenu.setMnemonic(getMnemonicInt("Window")); 196 // Add Window menu before Help menu 197 menuBar.add(windowMenu, menuBar.getComponentCount() - 1); 198 199 desktop = new JDesktopPane(); 200 desktop.setBackground(new Color(235, 245, 255)); 201 202 cp.add(desktop, BorderLayout.CENTER); 203 204 if (oldCenter instanceof VMPanel) { 205 addFrame((VMPanel)oldCenter); 206 } 207 } 208 209 private class WindowMenu extends JMenu { 210 VMInternalFrame[] windowMenuWindows = new VMInternalFrame[0]; 211 int separatorPosition; 212 213 // The width value of viewR is used to truncate long menu items. 214 // The rest are placeholders and are ignored for this purpose. 215 Rectangle viewR = new Rectangle(0, 0, 400, 20); 216 Rectangle textR = new Rectangle(0, 0, 0, 0); 217 Rectangle iconR = new Rectangle(0, 0, 0, 0); 218 219 WindowMenu(String text) { 220 super(text); 221 222 cascadeMI = new JMenuItem(Resources.getText("Cascade")); 223 cascadeMI.setMnemonic(getMnemonicInt("Cascade")); 224 cascadeMI.addActionListener(JConsole.this); 225 add(cascadeMI); 226 227 tileMI = new JMenuItem(Resources.getText("Tile")); 228 tileMI.setMnemonic(getMnemonicInt("Tile")); 229 tileMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 230 InputEvent.CTRL_MASK)); 231 tileMI.addActionListener(JConsole.this); 232 add(tileMI); 233 234 minimizeAllMI = new JMenuItem(Resources.getText("Minimize All")); 235 minimizeAllMI.setMnemonic(getMnemonicInt("Minimize All")); 236 minimizeAllMI.addActionListener(JConsole.this); 237 add(minimizeAllMI); 238 239 restoreAllMI = new JMenuItem(Resources.getText("Restore All")); 240 restoreAllMI.setMnemonic(getMnemonicInt("Restore All")); 241 restoreAllMI.addActionListener(JConsole.this); 242 add(restoreAllMI); 243 244 separatorPosition = getMenuComponentCount(); 245 } 246 247 private void add(VMInternalFrame vmIF) { 248 if (separatorPosition == getMenuComponentCount()) { 249 addSeparator(); 250 } 251 252 int index = -1; 253 int position = separatorPosition + 1; 254 int n = windowMenuWindows.length; 255 256 for (int i = 0; i < n; i++) { 257 if (windowMenuWindows[i] != null) { 258 // Slot is in use, try next 259 position++; 260 } else { 261 // Found a free slot 262 index = i; 263 break; 264 } 265 } 266 267 if (index == -1) { 268 // Create a slot at the end 269 VMInternalFrame[] newArray = new VMInternalFrame[n + 1]; 270 System.arraycopy(windowMenuWindows, 0, newArray, 0, n); 271 windowMenuWindows = newArray; 272 index = n; 273 } 274 275 windowMenuWindows[index] = vmIF; 276 277 String indexString = "" + (index+1); 278 String vmName = vmIF.getVMPanel().getDisplayName(); 279 // Maybe truncate menu item string and end with "..." 280 String text = 281 SwingUtilities.layoutCompoundLabel(this, 282 getGraphics().getFontMetrics(getFont()), 283 indexString + " " + vmName, 284 null, 0, 0, 0, 0, 285 viewR, iconR, textR, 0); 286 JMenuItem mi = new JMenuItem(text); 287 if (text.endsWith("...")) { 288 mi.setToolTipText(vmName); 289 } 290 291 // Set mnemonic using last digit of number 292 int nDigits = indexString.length(); 293 mi.setMnemonic(indexString.charAt(nDigits-1)); 294 mi.setDisplayedMnemonicIndex(nDigits-1); 295 296 mi.putClientProperty("JConsole.vmIF", vmIF); 297 mi.addActionListener(JConsole.this); 298 vmIF.putClientProperty("JConsole.menuItem", mi); 299 add(mi, position); 300 } 301 302 private void remove(VMInternalFrame vmIF) { 303 for (int i = 0; i < windowMenuWindows.length; i++) { 304 if (windowMenuWindows[i] == vmIF) { 305 windowMenuWindows[i] = null; 306 } 307 } 308 JMenuItem mi = (JMenuItem)vmIF.getClientProperty("JConsole.menuItem"); 309 remove(mi); 310 mi.putClientProperty("JConsole.vmIF", null); 311 vmIF.putClientProperty("JConsole.menuItem", null); 312 313 if (separatorPosition == getMenuComponentCount() - 1) { 314 remove(getMenuComponent(getMenuComponentCount() - 1)); 315 } 316 } 317 } 318 319 public void actionPerformed(ActionEvent ev) { 320 Object src = ev.getSource(); 321 if (src == hotspotMI) { 322 showCreateMBeanDialog(); 323 } 324 325 if (src == connectButton || src == connectMI) { 326 VMPanel vmPanel = null; 327 JInternalFrame vmIF = desktop.getSelectedFrame(); 328 if (vmIF instanceof VMInternalFrame) { 329 vmPanel = ((VMInternalFrame)vmIF).getVMPanel(); 330 } 331 String hostName = ""; 332 String url = ""; 333 if (vmPanel != null) { 334 hostName = vmPanel.getHostName(); 335 if(vmPanel.getUrl() != null) 336 url = vmPanel.getUrl(); 337 } 338 showConnectDialog(url, hostName, 0, null, null, null); 339 } else if (src == tileMI) { 340 tileWindows(); 341 } else if (src == cascadeMI) { 342 cascadeWindows(); 343 } else if (src == minimizeAllMI) { 344 for (VMInternalFrame vmIF : windows) { 345 try { 346 vmIF.setIcon(true); 347 } catch (PropertyVetoException ex) { 348 // Ignore 349 } 350 } 351 } else if (src == restoreAllMI) { 352 for (VMInternalFrame vmIF : windows) { 353 try { 354 vmIF.setIcon(false); 355 } catch (PropertyVetoException ex) { 356 // Ignore 357 } 358 } 359 } else if (src == exitMI) { 360 System.exit(0); 361 } else if (src == userGuideMI) { 362 AboutDialog.browseUserGuide(this); 363 } else if (src == aboutMI) { 364 AboutDialog.showAboutDialog(this); 365 } else if (src instanceof JMenuItem) { 366 JMenuItem mi = (JMenuItem)src; 367 VMInternalFrame vmIF = (VMInternalFrame)mi. 368 getClientProperty("JConsole.vmIF"); 369 if (vmIF != null) { 370 try { 371 vmIF.setIcon(false); 372 vmIF.setSelected(true); 373 } catch (PropertyVetoException ex) { 374 // Ignore 375 } 376 vmIF.moveToFront(); 377 } 378 } 379 } 380 381 382 public void tileWindows() { 383 int w = -1; 384 int h = -1; 385 int n = 0; 386 for (VMInternalFrame vmIF : windows) { 387 if (!vmIF.isIcon()) { 388 n++; 389 if (w == -1) { 390 try { 391 vmIF.setMaximum(true); 392 w = vmIF.getWidth(); 393 h = vmIF.getHeight(); 394 } catch (PropertyVetoException ex) { 395 // Ignore 396 } 397 } 398 } 399 } 400 if (n > 0 && w > 0 && h > 0) { 401 int rows = (int)Math.ceil(Math.sqrt(n)); 402 int cols = n / rows; 403 if (rows * cols < n) cols++; 404 int x = 0; 405 int y = 0; 406 w /= cols; 407 h /= rows; 408 int col = 0; 409 for (VMInternalFrame vmIF : windows) { 410 if (!vmIF.isIcon()) { 411 try { 412 vmIF.setMaximum(n==1); 413 } catch (PropertyVetoException ex) { 414 // Ignore 415 } 416 if (n > 1) { 417 vmIF.setBounds(x, y, w, h); 418 } 419 if (col < cols-1) { 420 col++; 421 x += w; 422 } else { 423 col = 0; 424 x = 0; 425 y += h; 426 } 427 } 428 } 429 } 430 } 431 432 public void cascadeWindows() { 433 int n = 0; 434 int w = -1; 435 int h = -1; 436 for (VMInternalFrame vmIF : windows) { 437 if (!vmIF.isIcon()) { 438 try { 439 vmIF.setMaximum(false); 440 } catch (PropertyVetoException ex) { 441 // Ignore 442 } 443 n++; 444 vmIF.pack(); 445 if (w == -1) { 446 try { 447 w = vmIF.getWidth(); 448 h = vmIF.getHeight(); 449 vmIF.setMaximum(true); 450 w = vmIF.getWidth() - w; 451 h = vmIF.getHeight() - h; 452 vmIF.pack(); 453 } catch (PropertyVetoException ex) { 454 // Ignore 455 } 456 } 457 } 458 } 459 int x = 0; 460 int y = 0; 461 int dX = (n > 1) ? (w / (n - 1)) : 0; 462 int dY = (n > 1) ? (h / (n - 1)) : 0; 463 for (VMInternalFrame vmIF : windows) { 464 if (!vmIF.isIcon()) { 465 vmIF.setLocation(x, y); 466 vmIF.moveToFront(); 467 x += dX; 468 y += dY; 469 } 470 } 471 } 472 473 // Call on EDT 474 void addHost(String hostName, int port, 475 String userName, String password) { 476 addHost(hostName, port, userName, password, false); 477 } 478 479 // Call on EDT 480 void addVmid(LocalVirtualMachine lvm) { 481 addVmid(lvm, false); 482 } 483 484 // Call on EDT 485 void addVmid(final LocalVirtualMachine lvm, final boolean tile) { 486 new Thread("JConsole.addVmid") { 487 public void run() { 488 try { 489 addProxyClient(ProxyClient.getProxyClient(lvm), tile); 490 } catch (final SecurityException ex) { 491 failed(ex, null, null, null); 492 } catch (final IOException ex) { 493 failed(ex, null, null, null); 494 } 495 } 496 }.start(); 497 } 498 499 // Call on EDT 500 void addUrl(final String url, 501 final String userName, 502 final String password, 503 final boolean tile) { 504 new Thread("JConsole.addUrl") { 505 public void run() { 506 try { 507 addProxyClient(ProxyClient.getProxyClient(url, userName, password), 508 tile); 509 } catch (final MalformedURLException ex) { 510 failed(ex, url, userName, password); 511 } catch (final SecurityException ex) { 512 failed(ex, url, userName, password); 513 } catch (final IOException ex) { 514 failed(ex, url, userName, password); 515 } 516 } 517 }.start(); 518 } 519 520 521 // Call on EDT 522 void addHost(final String hostName, final int port, 523 final String userName, final String password, 524 final boolean tile) { 525 new Thread("JConsole.addHost") { 526 public void run() { 527 try { 528 addProxyClient(ProxyClient.getProxyClient(hostName, port, 529 userName, password), 530 tile); 531 } catch (final IOException ex) { 532 dbgStackTrace(ex); 533 SwingUtilities.invokeLater(new Runnable() { 534 public void run() { 535 showConnectDialog(null, hostName, port, 536 userName, password, errorMessage(ex)); 537 } 538 }); 539 } 540 } 541 }.start(); 542 } 543 544 545 // Call on worker thread 546 void addProxyClient(final ProxyClient proxyClient, final boolean tile) { 547 SwingUtilities.invokeLater(new Runnable() { 548 public void run() { 549 VMPanel vmPanel = new VMPanel(proxyClient, updateInterval); 550 addFrame(vmPanel); 551 552 if (tile) { 553 SwingUtilities.invokeLater(new Runnable() { 554 public void run() { 555 tileWindows(); 556 } 557 }); 558 } 559 vmPanel.connect(); 560 } 561 }); 562 } 563 564 565 // Call on worker thread 566 private void failed(final Exception ex, 567 final String url, 568 final String userName, 569 final String password) { 570 SwingUtilities.invokeLater(new Runnable() { 571 public void run() { 572 dbgStackTrace(ex); 573 showConnectDialog(url, 574 null, 575 -1, 576 userName, 577 password, 578 errorMessage(ex)); 579 } 580 }); 581 } 582 583 584 private VMInternalFrame addFrame(VMPanel vmPanel) { 585 final VMInternalFrame vmIF = new VMInternalFrame(vmPanel); 586 587 for (VMInternalFrame f : windows) { 588 try { 589 f.setMaximum(false); 590 } catch (PropertyVetoException ex) { 591 // Ignore 592 } 593 } 594 desktop.add(vmIF); 595 596 vmIF.setLocation(frameLoc, frameLoc); 597 frameLoc += 30; 598 vmIF.setVisible(true); 599 windows.add(vmIF); 600 if (windows.size() == 1) { 601 try { 602 vmIF.setMaximum(true); 603 } catch (PropertyVetoException ex) { 604 // Ignore 605 } 606 } 607 vmIF.addInternalFrameListener(this); 608 windowMenu.add(vmIF); 609 610 return vmIF; 611 } 612 613 private void showConnectDialog(String url, 614 String hostName, 615 int port, 616 String userName, 617 String password, 618 String msg) { 619 if (connectDialog == null) { 620 connectDialog = new ConnectDialog(this); 621 } 622 connectDialog.setConnectionParameters(url, 623 hostName, 624 port, 625 userName, 626 password, 627 msg); 628 629 connectDialog.refresh(); 630 connectDialog.setVisible(true); 631 try { 632 // Bring to front of other dialogs 633 connectDialog.setSelected(true); 634 } catch (PropertyVetoException e) { 635 } 636 } 637 638 private void showCreateMBeanDialog() { 639 if (createDialog == null) { 640 createDialog = new CreateMBeanDialog(this); 641 } 642 createDialog.setVisible(true); 643 try { 644 // Bring to front of other dialogs 645 createDialog.setSelected(true); 646 } catch (PropertyVetoException e) { 647 } 648 } 649 650 private void removeVMInternalFrame(VMInternalFrame vmIF) { 651 windowMenu.remove(vmIF); 652 desktop.remove(vmIF); 653 desktop.repaint(); 654 vmIF.getVMPanel().cleanUp(); 655 vmIF.dispose(); 656 } 657 658 private boolean isProxyClientUsed(ProxyClient client) { 659 for(VMInternalFrame frame : windows) { 660 ProxyClient cli = frame.getVMPanel().getProxyClient(false); 661 if(client == cli) 662 return true; 663 } 664 return false; 665 } 666 667 static boolean isValidRemoteString(String txt) { 668 boolean valid = false; 669 if (txt != null) { 670 txt = txt.trim(); 671 if (txt.startsWith(ROOT_URL)) { 672 if (txt.length() > ROOT_URL.length()) { 673 valid = true; 674 } 675 } else { 676 //--------------------------------------- 677 // Supported host and port combinations: 678 // hostname:port 679 // IPv4Address:port 680 // [IPv6Address]:port 681 //--------------------------------------- 682 683 // Is literal IPv6 address? 684 // 685 if (txt.startsWith("[")) { 686 int index = txt.indexOf("]:"); 687 if (index != -1) { 688 // Extract literal IPv6 address 689 // 690 String address = txt.substring(1, index); 691 if (IPAddressUtil.isIPv6LiteralAddress(address)) { 692 // Extract port 693 // 694 try { 695 String portStr = txt.substring(index + 2); 696 int port = Integer.parseInt(portStr); 697 if (port >= 0 && port <= 0xFFFF) { 698 valid = true; 699 } 700 } catch (NumberFormatException ex) { 701 valid = false; 702 } 703 } 704 } 705 } else { 706 String[] s = txt.split(":"); 707 if (s.length == 2) { 708 try { 709 int port = Integer.parseInt(s[1]); 710 if (port >= 0 && port <= 0xFFFF) { 711 valid = true; 712 } 713 } catch (NumberFormatException ex) { 714 valid = false; 715 } 716 } 717 } 718 } 719 } 720 return valid; 721 } 722 723 private String errorMessage(Exception ex) { 724 String msg = Resources.getText("Connection failed"); 725 if (ex instanceof IOException || ex instanceof SecurityException) { 726 Throwable cause = null; 727 Throwable c = ex.getCause(); 728 while (c != null) { 729 cause = c; 730 c = c.getCause(); 731 } 732 if (cause instanceof ConnectException) { 733 return msg + ": " + cause.getMessage(); 734 } else if (cause instanceof UnknownHostException) { 735 return Resources.getText("Unknown Host", cause.getMessage()); 736 } else if (cause instanceof NoRouteToHostException) { 737 return msg + ": " + cause.getMessage(); 738 } else if (cause instanceof FailedLoginException) { 739 return msg + ": " + cause.getMessage(); 740 } else if (cause instanceof SSLHandshakeException) { 741 return msg + ": "+ cause.getMessage(); 742 } 743 } else if (ex instanceof MalformedURLException) { 744 return Resources.getText("Invalid URL", ex.getMessage()); 745 } 746 return msg + ": " + ex.getMessage(); 747 } 748 749 750 // InternalFrameListener interface 751 752 public void internalFrameClosing(InternalFrameEvent e) { 753 VMInternalFrame vmIF = (VMInternalFrame)e.getInternalFrame(); 754 removeVMInternalFrame(vmIF); 755 windows.remove(vmIF); 756 ProxyClient client = vmIF.getVMPanel().getProxyClient(false); 757 if(!isProxyClientUsed(client)) 758 client.markAsDead(); 759 if (windows.size() == 0) { 760 showConnectDialog("", "", 0, null, null, null); 761 } 762 } 763 764 public void internalFrameOpened(InternalFrameEvent e) {} 765 public void internalFrameClosed(InternalFrameEvent e) {} 766 public void internalFrameIconified(InternalFrameEvent e) {} 767 public void internalFrameDeiconified(InternalFrameEvent e) {} 768 public void internalFrameActivated(InternalFrameEvent e) {} 769 public void internalFrameDeactivated(InternalFrameEvent e) {} 770 771 772 private static void usage() { 773 System.err.println(Resources.getText("zz usage text", "jconsole")); 774 } 775 776 private static void mainInit(final List<String> urls, 777 final List<String> hostNames, 778 final List<Integer> ports, 779 final List<LocalVirtualMachine> vmids, 780 final ProxyClient proxyClient, 781 final boolean noTile, 782 final boolean hotspot) { 783 784 785 // Always create Swing GUI on the Event Dispatching Thread 786 SwingUtilities.invokeLater(new Runnable() { 787 public void run() { 788 JConsole jConsole = new JConsole(hotspot); 789 790 // Center the window on screen, taking into account screen 791 // size and insets. 792 Toolkit toolkit = Toolkit.getDefaultToolkit(); 793 GraphicsConfiguration gc = jConsole.getGraphicsConfiguration(); 794 Dimension scrSize = toolkit.getScreenSize(); 795 Insets scrInsets = toolkit.getScreenInsets(gc); 796 Rectangle scrBounds = 797 new Rectangle(scrInsets.left, scrInsets.top, 798 scrSize.width - scrInsets.left - scrInsets.right, 799 scrSize.height - scrInsets.top - scrInsets.bottom); 800 int w = Math.min(900, scrBounds.width); 801 int h = Math.min(750, scrBounds.height); 802 jConsole.setBounds(scrBounds.x + (scrBounds.width - w) / 2, 803 scrBounds.y + (scrBounds.height - h) / 2, 804 w, h); 805 806 jConsole.setVisible(true); 807 jConsole.createMDI(); 808 809 for (int i = 0; i < hostNames.size(); i++) { 810 jConsole.addHost(hostNames.get(i), ports.get(i), 811 null, null, 812 (i == hostNames.size() - 1) ? 813 !noTile : false); 814 } 815 816 for (int i = 0; i < urls.size(); i++) { 817 jConsole.addUrl(urls.get(i), 818 null, 819 null, 820 (i == urls.size() - 1) ? 821 !noTile : false); 822 } 823 824 for (int i = 0; i < vmids.size(); i++) { 825 jConsole.addVmid(vmids.get(i), 826 (i == vmids.size() - 1) ? 827 !noTile : false); 828 } 829 830 if (vmids.size() == 0 && 831 hostNames.size() == 0 && 832 urls.size() == 0) { 833 jConsole.showConnectDialog(null, 834 null, 835 0, 836 null, 837 null, 838 null); 839 } 840 } 841 }); 842 } 843 844 public static void main(String[] args) { 845 boolean noTile = false, hotspot = false; 846 int argIndex = 0; 847 ProxyClient proxyClient = null; 848 849 if (System.getProperty("jconsole.showOutputViewer") != null) { 850 OutputViewer.init(); 851 } 852 853 while (args.length - argIndex > 0 && args[argIndex].startsWith("-")) { 854 String arg = args[argIndex++]; 855 if (arg.equals("-h") || 856 arg.equals("-help") || 857 arg.equals("-?")) { 858 859 usage(); 860 return; 861 } else if (arg.startsWith("-interval=")) { 862 try { 863 updateInterval = Integer.parseInt(arg.substring(10)) * 864 1000; 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.getText("Fail to load plugin", 1007 e.getMessage())); 1008 } catch (MalformedURLException e) { 1009 if (JConsole.isDebug()) { 1010 e.printStackTrace(); 1011 } 1012 System.out.println(Resources.getText("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 }