0001: /*
0002: * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.jconsole;
0027:
0028: import java.awt.*;
0029: import java.awt.event.*;
0030: import java.beans.*;
0031: import java.io.*;
0032: import java.lang.reflect.InvocationTargetException;
0033: import java.net.*;
0034: import java.util.*;
0035: import java.util.List;
0036:
0037: import javax.swing.*;
0038: import javax.swing.border.*;
0039: import javax.swing.event.*;
0040: import javax.swing.plaf.*;
0041: import javax.management.remote.JMXServiceURL;
0042: import javax.management.remote.JMXConnector;
0043: import javax.security.auth.login.FailedLoginException;
0044: import javax.net.ssl.SSLHandshakeException;
0045:
0046: import com.sun.tools.jconsole.JConsolePlugin;
0047:
0048: import sun.net.util.IPAddressUtil;
0049:
0050: import static sun.tools.jconsole.Resources.*;
0051: import static sun.tools.jconsole.Utilities.*;
0052:
0053: @SuppressWarnings("serial")
0054: public class JConsole extends JFrame implements ActionListener,
0055: InternalFrameListener {
0056:
0057: static/*final*/boolean IS_GTK;
0058: static/*final*/boolean IS_WIN;
0059:
0060: static {
0061: // Apply the system L&F if it is GTK or Windows, and
0062: // the L&F is not specified using a system property.
0063: if (System.getProperty("swing.defaultlaf") == null) {
0064: String systemLaF = UIManager
0065: .getSystemLookAndFeelClassName();
0066: if (systemLaF
0067: .equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")
0068: || systemLaF
0069: .equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) {
0070:
0071: try {
0072: UIManager.setLookAndFeel(systemLaF);
0073: } catch (Exception e) {
0074: System.err.println(Resources.getText("JConsole: ",
0075: e.getMessage()));
0076: }
0077: }
0078: }
0079:
0080: updateLafValues();
0081: }
0082:
0083: static void updateLafValues() {
0084: String lafName = UIManager.getLookAndFeel().getClass()
0085: .getName();
0086: IS_GTK = lafName
0087: .equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
0088: IS_WIN = lafName
0089: .equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
0090:
0091: //BorderedComponent.updateLafValues();
0092: }
0093:
0094: private final static String title = Resources
0095: .getText("Java Monitoring & Management Console");
0096: public final static String ROOT_URL = "service:jmx:";
0097:
0098: private static int updateInterval = 4000;
0099: private static String pluginPath = "";
0100:
0101: private JMenuBar menuBar;
0102: private JMenuItem hotspotMI, connectMI, exitMI;
0103: private WindowMenu windowMenu;
0104: private JMenuItem tileMI, cascadeMI, minimizeAllMI, restoreAllMI;
0105: private JMenuItem userGuideMI, aboutMI;
0106:
0107: private JButton connectButton;
0108: private JDesktopPane desktop;
0109: private ConnectDialog connectDialog;
0110: private CreateMBeanDialog createDialog;
0111:
0112: private ArrayList<VMInternalFrame> windows = new ArrayList<VMInternalFrame>();
0113:
0114: private int frameLoc = 5;
0115: static boolean debug;
0116:
0117: public JConsole(boolean hotspot) {
0118: super (title);
0119:
0120: setRootPane(new FixedJRootPane());
0121: setAccessibleDescription(this ,
0122: getText("JConsole.accessibleDescription"));
0123: setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
0124:
0125: menuBar = new JMenuBar();
0126: setJMenuBar(menuBar);
0127:
0128: // TODO: Use Actions !
0129:
0130: JMenu connectionMenu = new JMenu(getText("Connection"));
0131: connectionMenu.setMnemonic(getMnemonicInt("Connection"));
0132: menuBar.add(connectionMenu);
0133: if (hotspot) {
0134: hotspotMI = new JMenuItem(getText("Hotspot MBeans..."));
0135: hotspotMI.setMnemonic(getMnemonicInt("Hotspot MBeans..."));
0136: hotspotMI.setAccelerator(KeyStroke.getKeyStroke(
0137: KeyEvent.VK_H, InputEvent.CTRL_MASK));
0138: hotspotMI.addActionListener(this );
0139: connectionMenu.add(hotspotMI);
0140:
0141: connectionMenu.addSeparator();
0142: }
0143:
0144: connectMI = new JMenuItem(Resources
0145: .getText("New Connection..."));
0146: connectMI.setMnemonic(getMnemonicInt("New Connection..."));
0147: connectMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
0148: InputEvent.CTRL_MASK));
0149: connectMI.addActionListener(this );
0150: connectionMenu.add(connectMI);
0151:
0152: connectionMenu.addSeparator();
0153:
0154: exitMI = new JMenuItem(Resources.getText("Exit"));
0155: exitMI.setMnemonic(getMnemonicInt("Exit"));
0156: exitMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4,
0157: InputEvent.ALT_MASK));
0158: exitMI.addActionListener(this );
0159: connectionMenu.add(exitMI);
0160:
0161: JMenu helpMenu = new JMenu(getText("HelpMenu.title"));
0162: helpMenu.setMnemonic(getMnemonicInt("HelpMenu.title"));
0163: menuBar.add(helpMenu);
0164:
0165: if (AboutDialog.isBrowseSupported()) {
0166: userGuideMI = new JMenuItem(
0167: getText("HelpMenu.UserGuide.title"));
0168: userGuideMI
0169: .setMnemonic(getMnemonicInt("HelpMenu.UserGuide.title"));
0170: userGuideMI.addActionListener(this );
0171: helpMenu.add(userGuideMI);
0172: helpMenu.addSeparator();
0173: }
0174: aboutMI = new JMenuItem(getText("HelpMenu.About.title"));
0175: aboutMI.setMnemonic(getMnemonicInt("HelpMenu.About.title"));
0176: aboutMI.setAccelerator(KeyStroke
0177: .getKeyStroke(KeyEvent.VK_F1, 0));
0178: aboutMI.addActionListener(this );
0179: helpMenu.add(aboutMI);
0180: }
0181:
0182: public JDesktopPane getDesktopPane() {
0183: return desktop;
0184: }
0185:
0186: public List<VMInternalFrame> getInternalFrames() {
0187: return windows;
0188: }
0189:
0190: private void createMDI() {
0191: // Restore title - we now show connection name on internal frames
0192: setTitle(title);
0193:
0194: Container cp = getContentPane();
0195: Component oldCenter = ((BorderLayout) cp.getLayout())
0196: .getLayoutComponent(BorderLayout.CENTER);
0197:
0198: windowMenu = new WindowMenu(Resources.getText("Window"));
0199: windowMenu.setMnemonic(getMnemonicInt("Window"));
0200: // Add Window menu before Help menu
0201: menuBar.add(windowMenu, menuBar.getComponentCount() - 1);
0202:
0203: desktop = new JDesktopPane();
0204: desktop.setBackground(new Color(235, 245, 255));
0205:
0206: cp.add(desktop, BorderLayout.CENTER);
0207:
0208: if (oldCenter instanceof VMPanel) {
0209: addFrame((VMPanel) oldCenter);
0210: }
0211: }
0212:
0213: private class WindowMenu extends JMenu {
0214: VMInternalFrame[] windowMenuWindows = new VMInternalFrame[0];
0215: int separatorPosition;
0216:
0217: // The width value of viewR is used to truncate long menu items.
0218: // The rest are placeholders and are ignored for this purpose.
0219: Rectangle viewR = new Rectangle(0, 0, 400, 20);
0220: Rectangle textR = new Rectangle(0, 0, 0, 0);
0221: Rectangle iconR = new Rectangle(0, 0, 0, 0);
0222:
0223: WindowMenu(String text) {
0224: super (text);
0225:
0226: cascadeMI = new JMenuItem(Resources.getText("Cascade"));
0227: cascadeMI.setMnemonic(getMnemonicInt("Cascade"));
0228: cascadeMI.addActionListener(JConsole.this );
0229: add(cascadeMI);
0230:
0231: tileMI = new JMenuItem(Resources.getText("Tile"));
0232: tileMI.setMnemonic(getMnemonicInt("Tile"));
0233: tileMI.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
0234: InputEvent.CTRL_MASK));
0235: tileMI.addActionListener(JConsole.this );
0236: add(tileMI);
0237:
0238: minimizeAllMI = new JMenuItem(Resources
0239: .getText("Minimize All"));
0240: minimizeAllMI.setMnemonic(getMnemonicInt("Minimize All"));
0241: minimizeAllMI.addActionListener(JConsole.this );
0242: add(minimizeAllMI);
0243:
0244: restoreAllMI = new JMenuItem(Resources
0245: .getText("Restore All"));
0246: restoreAllMI.setMnemonic(getMnemonicInt("Restore All"));
0247: restoreAllMI.addActionListener(JConsole.this );
0248: add(restoreAllMI);
0249:
0250: separatorPosition = getMenuComponentCount();
0251: }
0252:
0253: private void add(VMInternalFrame vmIF) {
0254: if (separatorPosition == getMenuComponentCount()) {
0255: addSeparator();
0256: }
0257:
0258: int index = -1;
0259: int position = separatorPosition + 1;
0260: int n = windowMenuWindows.length;
0261:
0262: for (int i = 0; i < n; i++) {
0263: if (windowMenuWindows[i] != null) {
0264: // Slot is in use, try next
0265: position++;
0266: } else {
0267: // Found a free slot
0268: index = i;
0269: break;
0270: }
0271: }
0272:
0273: if (index == -1) {
0274: // Create a slot at the end
0275: VMInternalFrame[] newArray = new VMInternalFrame[n + 1];
0276: System.arraycopy(windowMenuWindows, 0, newArray, 0, n);
0277: windowMenuWindows = newArray;
0278: index = n;
0279: }
0280:
0281: windowMenuWindows[index] = vmIF;
0282:
0283: String indexString = "" + (index + 1);
0284: String vmName = vmIF.getVMPanel().getDisplayName();
0285: // Maybe truncate menu item string and end with "..."
0286: String text = SwingUtilities.layoutCompoundLabel(this ,
0287: getGraphics().getFontMetrics(getFont()),
0288: indexString + " " + vmName, null, 0, 0, 0, 0,
0289: viewR, iconR, textR, 0);
0290: JMenuItem mi = new JMenuItem(text);
0291: if (text.endsWith("...")) {
0292: mi.setToolTipText(vmName);
0293: }
0294:
0295: // Set mnemonic using last digit of number
0296: int nDigits = indexString.length();
0297: mi.setMnemonic(indexString.charAt(nDigits - 1));
0298: mi.setDisplayedMnemonicIndex(nDigits - 1);
0299:
0300: mi.putClientProperty("JConsole.vmIF", vmIF);
0301: mi.addActionListener(JConsole.this );
0302: vmIF.putClientProperty("JConsole.menuItem", mi);
0303: add(mi, position);
0304: }
0305:
0306: private void remove(VMInternalFrame vmIF) {
0307: for (int i = 0; i < windowMenuWindows.length; i++) {
0308: if (windowMenuWindows[i] == vmIF) {
0309: windowMenuWindows[i] = null;
0310: }
0311: }
0312: JMenuItem mi = (JMenuItem) vmIF
0313: .getClientProperty("JConsole.menuItem");
0314: remove(mi);
0315: mi.putClientProperty("JConsole.vmIF", null);
0316: vmIF.putClientProperty("JConsole.menuItem", null);
0317:
0318: if (separatorPosition == getMenuComponentCount() - 1) {
0319: remove(getMenuComponent(getMenuComponentCount() - 1));
0320: }
0321: }
0322: }
0323:
0324: public void actionPerformed(ActionEvent ev) {
0325: Object src = ev.getSource();
0326: if (src == hotspotMI) {
0327: showCreateMBeanDialog();
0328: }
0329:
0330: if (src == connectButton || src == connectMI) {
0331: VMPanel vmPanel = null;
0332: JInternalFrame vmIF = desktop.getSelectedFrame();
0333: if (vmIF instanceof VMInternalFrame) {
0334: vmPanel = ((VMInternalFrame) vmIF).getVMPanel();
0335: }
0336: String hostName = "";
0337: String url = "";
0338: if (vmPanel != null) {
0339: hostName = vmPanel.getHostName();
0340: if (vmPanel.getUrl() != null)
0341: url = vmPanel.getUrl();
0342: }
0343: showConnectDialog(url, hostName, 0, null, null, null);
0344: } else if (src == tileMI) {
0345: tileWindows();
0346: } else if (src == cascadeMI) {
0347: cascadeWindows();
0348: } else if (src == minimizeAllMI) {
0349: for (VMInternalFrame vmIF : windows) {
0350: try {
0351: vmIF.setIcon(true);
0352: } catch (PropertyVetoException ex) {
0353: // Ignore
0354: }
0355: }
0356: } else if (src == restoreAllMI) {
0357: for (VMInternalFrame vmIF : windows) {
0358: try {
0359: vmIF.setIcon(false);
0360: } catch (PropertyVetoException ex) {
0361: // Ignore
0362: }
0363: }
0364: } else if (src == exitMI) {
0365: System.exit(0);
0366: } else if (src == userGuideMI) {
0367: AboutDialog.browseUserGuide(this );
0368: } else if (src == aboutMI) {
0369: AboutDialog.showAboutDialog(this );
0370: } else if (src instanceof JMenuItem) {
0371: JMenuItem mi = (JMenuItem) src;
0372: VMInternalFrame vmIF = (VMInternalFrame) mi
0373: .getClientProperty("JConsole.vmIF");
0374: if (vmIF != null) {
0375: try {
0376: vmIF.setIcon(false);
0377: vmIF.setSelected(true);
0378: } catch (PropertyVetoException ex) {
0379: // Ignore
0380: }
0381: vmIF.moveToFront();
0382: }
0383: }
0384: }
0385:
0386: public void tileWindows() {
0387: int w = -1;
0388: int h = -1;
0389: int n = 0;
0390: for (VMInternalFrame vmIF : windows) {
0391: if (!vmIF.isIcon()) {
0392: n++;
0393: if (w == -1) {
0394: try {
0395: vmIF.setMaximum(true);
0396: w = vmIF.getWidth();
0397: h = vmIF.getHeight();
0398: } catch (PropertyVetoException ex) {
0399: // Ignore
0400: }
0401: }
0402: }
0403: }
0404: if (n > 0 && w > 0 && h > 0) {
0405: int rows = (int) Math.ceil(Math.sqrt(n));
0406: int cols = n / rows;
0407: if (rows * cols < n)
0408: cols++;
0409: int x = 0;
0410: int y = 0;
0411: w /= cols;
0412: h /= rows;
0413: int col = 0;
0414: for (VMInternalFrame vmIF : windows) {
0415: if (!vmIF.isIcon()) {
0416: try {
0417: vmIF.setMaximum(n == 1);
0418: } catch (PropertyVetoException ex) {
0419: // Ignore
0420: }
0421: if (n > 1) {
0422: vmIF.setBounds(x, y, w, h);
0423: }
0424: if (col < cols - 1) {
0425: col++;
0426: x += w;
0427: } else {
0428: col = 0;
0429: x = 0;
0430: y += h;
0431: }
0432: }
0433: }
0434: }
0435: }
0436:
0437: public void cascadeWindows() {
0438: int n = 0;
0439: int w = -1;
0440: int h = -1;
0441: for (VMInternalFrame vmIF : windows) {
0442: if (!vmIF.isIcon()) {
0443: try {
0444: vmIF.setMaximum(false);
0445: } catch (PropertyVetoException ex) {
0446: // Ignore
0447: }
0448: n++;
0449: vmIF.pack();
0450: if (w == -1) {
0451: try {
0452: w = vmIF.getWidth();
0453: h = vmIF.getHeight();
0454: vmIF.setMaximum(true);
0455: w = vmIF.getWidth() - w;
0456: h = vmIF.getHeight() - h;
0457: vmIF.pack();
0458: } catch (PropertyVetoException ex) {
0459: // Ignore
0460: }
0461: }
0462: }
0463: }
0464: int x = 0;
0465: int y = 0;
0466: int dX = (n > 1) ? (w / (n - 1)) : 0;
0467: int dY = (n > 1) ? (h / (n - 1)) : 0;
0468: for (VMInternalFrame vmIF : windows) {
0469: if (!vmIF.isIcon()) {
0470: vmIF.setLocation(x, y);
0471: vmIF.moveToFront();
0472: x += dX;
0473: y += dY;
0474: }
0475: }
0476: }
0477:
0478: // Call on EDT
0479: void addHost(String hostName, int port, String userName,
0480: String password) {
0481: addHost(hostName, port, userName, password, false);
0482: }
0483:
0484: // Call on EDT
0485: void addVmid(LocalVirtualMachine lvm) {
0486: addVmid(lvm, false);
0487: }
0488:
0489: // Call on EDT
0490: void addVmid(final LocalVirtualMachine lvm, final boolean tile) {
0491: new Thread("JConsole.addVmid") {
0492: public void run() {
0493: try {
0494: addProxyClient(ProxyClient.getProxyClient(lvm),
0495: tile);
0496: } catch (final SecurityException ex) {
0497: failed(ex, null, null, null);
0498: } catch (final IOException ex) {
0499: failed(ex, null, null, null);
0500: }
0501: }
0502: }.start();
0503: }
0504:
0505: // Call on EDT
0506: void addUrl(final String url, final String userName,
0507: final String password, final boolean tile) {
0508: new Thread("JConsole.addUrl") {
0509: public void run() {
0510: try {
0511: addProxyClient(ProxyClient.getProxyClient(url,
0512: userName, password), tile);
0513: } catch (final MalformedURLException ex) {
0514: failed(ex, url, userName, password);
0515: } catch (final SecurityException ex) {
0516: failed(ex, url, userName, password);
0517: } catch (final IOException ex) {
0518: failed(ex, url, userName, password);
0519: }
0520: }
0521: }.start();
0522: }
0523:
0524: // Call on EDT
0525: void addHost(final String hostName, final int port,
0526: final String userName, final String password,
0527: final boolean tile) {
0528: new Thread("JConsole.addHost") {
0529: public void run() {
0530: try {
0531: addProxyClient(ProxyClient.getProxyClient(hostName,
0532: port, userName, password), tile);
0533: } catch (final IOException ex) {
0534: dbgStackTrace(ex);
0535: SwingUtilities.invokeLater(new Runnable() {
0536: public void run() {
0537: showConnectDialog(null, hostName, port,
0538: userName, password,
0539: errorMessage(ex));
0540: }
0541: });
0542: }
0543: }
0544: }.start();
0545: }
0546:
0547: // Call on worker thread
0548: void addProxyClient(final ProxyClient proxyClient,
0549: final boolean tile) {
0550: SwingUtilities.invokeLater(new Runnable() {
0551: public void run() {
0552: VMPanel vmPanel = new VMPanel(proxyClient,
0553: updateInterval);
0554: addFrame(vmPanel);
0555:
0556: if (tile) {
0557: SwingUtilities.invokeLater(new Runnable() {
0558: public void run() {
0559: tileWindows();
0560: }
0561: });
0562: }
0563: vmPanel.connect();
0564: }
0565: });
0566: }
0567:
0568: // Call on worker thread
0569: private void failed(final Exception ex, final String url,
0570: final String userName, final String password) {
0571: SwingUtilities.invokeLater(new Runnable() {
0572: public void run() {
0573: dbgStackTrace(ex);
0574: showConnectDialog(url, null, -1, userName, password,
0575: errorMessage(ex));
0576: }
0577: });
0578: }
0579:
0580: private VMInternalFrame addFrame(VMPanel vmPanel) {
0581: final VMInternalFrame vmIF = new VMInternalFrame(vmPanel);
0582:
0583: for (VMInternalFrame f : windows) {
0584: try {
0585: f.setMaximum(false);
0586: } catch (PropertyVetoException ex) {
0587: // Ignore
0588: }
0589: }
0590: desktop.add(vmIF);
0591:
0592: vmIF.setLocation(frameLoc, frameLoc);
0593: frameLoc += 30;
0594: vmIF.setVisible(true);
0595: windows.add(vmIF);
0596: if (windows.size() == 1) {
0597: try {
0598: vmIF.setMaximum(true);
0599: } catch (PropertyVetoException ex) {
0600: // Ignore
0601: }
0602: }
0603: vmIF.addInternalFrameListener(this );
0604: windowMenu.add(vmIF);
0605:
0606: return vmIF;
0607: }
0608:
0609: private void showConnectDialog(String url, String hostName,
0610: int port, String userName, String password, String msg) {
0611: if (connectDialog == null) {
0612: connectDialog = new ConnectDialog(this );
0613: }
0614: connectDialog.setConnectionParameters(url, hostName, port,
0615: userName, password, msg);
0616:
0617: connectDialog.refresh();
0618: connectDialog.setVisible(true);
0619: try {
0620: // Bring to front of other dialogs
0621: connectDialog.setSelected(true);
0622: } catch (PropertyVetoException e) {
0623: }
0624: }
0625:
0626: private void showCreateMBeanDialog() {
0627: if (createDialog == null) {
0628: createDialog = new CreateMBeanDialog(this );
0629: }
0630: createDialog.setVisible(true);
0631: try {
0632: // Bring to front of other dialogs
0633: createDialog.setSelected(true);
0634: } catch (PropertyVetoException e) {
0635: }
0636: }
0637:
0638: private void removeVMInternalFrame(VMInternalFrame vmIF) {
0639: windowMenu.remove(vmIF);
0640: desktop.remove(vmIF);
0641: desktop.repaint();
0642: vmIF.getVMPanel().cleanUp();
0643: vmIF.dispose();
0644: }
0645:
0646: private boolean isProxyClientUsed(ProxyClient client) {
0647: for (VMInternalFrame frame : windows) {
0648: ProxyClient cli = frame.getVMPanel().getProxyClient(false);
0649: if (client == cli)
0650: return true;
0651: }
0652: return false;
0653: }
0654:
0655: static boolean isValidRemoteString(String txt) {
0656: boolean valid = false;
0657: if (txt != null) {
0658: txt = txt.trim();
0659: if (txt.startsWith(ROOT_URL)) {
0660: if (txt.length() > ROOT_URL.length()) {
0661: valid = true;
0662: }
0663: } else {
0664: //---------------------------------------
0665: // Supported host and port combinations:
0666: // hostname:port
0667: // IPv4Address:port
0668: // [IPv6Address]:port
0669: //---------------------------------------
0670:
0671: // Is literal IPv6 address?
0672: //
0673: if (txt.startsWith("[")) {
0674: int index = txt.indexOf("]:");
0675: if (index != -1) {
0676: // Extract literal IPv6 address
0677: //
0678: String address = txt.substring(1, index);
0679: if (IPAddressUtil.isIPv6LiteralAddress(address)) {
0680: // Extract port
0681: //
0682: try {
0683: String portStr = txt
0684: .substring(index + 2);
0685: int port = Integer.parseInt(portStr);
0686: if (port >= 0 && port <= 0xFFFF) {
0687: valid = true;
0688: }
0689: } catch (NumberFormatException ex) {
0690: valid = false;
0691: }
0692: }
0693: }
0694: } else {
0695: String[] s = txt.split(":");
0696: if (s.length == 2) {
0697: try {
0698: int port = Integer.parseInt(s[1]);
0699: if (port >= 0 && port <= 0xFFFF) {
0700: valid = true;
0701: }
0702: } catch (NumberFormatException ex) {
0703: valid = false;
0704: }
0705: }
0706: }
0707: }
0708: }
0709: return valid;
0710: }
0711:
0712: private String errorMessage(Exception ex) {
0713: String msg = Resources.getText("Connection failed");
0714: if (ex instanceof IOException
0715: || ex instanceof SecurityException) {
0716: Throwable cause = null;
0717: Throwable c = ex.getCause();
0718: while (c != null) {
0719: cause = c;
0720: c = c.getCause();
0721: }
0722: if (cause instanceof ConnectException) {
0723: return msg + ": " + cause.getMessage();
0724: } else if (cause instanceof UnknownHostException) {
0725: return Resources.getText("Unknown Host", cause
0726: .getMessage());
0727: } else if (cause instanceof NoRouteToHostException) {
0728: return msg + ": " + cause.getMessage();
0729: } else if (cause instanceof FailedLoginException) {
0730: return msg + ": " + cause.getMessage();
0731: } else if (cause instanceof SSLHandshakeException) {
0732: return msg + ": " + cause.getMessage();
0733: }
0734: } else if (ex instanceof MalformedURLException) {
0735: return Resources.getText("Invalid URL", ex.getMessage());
0736: }
0737: return msg + ": " + ex.getMessage();
0738: }
0739:
0740: // InternalFrameListener interface
0741:
0742: public void internalFrameClosing(InternalFrameEvent e) {
0743: VMInternalFrame vmIF = (VMInternalFrame) e.getInternalFrame();
0744: removeVMInternalFrame(vmIF);
0745: windows.remove(vmIF);
0746: ProxyClient client = vmIF.getVMPanel().getProxyClient(false);
0747: if (!isProxyClientUsed(client))
0748: client.markAsDead();
0749: if (windows.size() == 0) {
0750: showConnectDialog("", "", 0, null, null, null);
0751: }
0752: }
0753:
0754: public void internalFrameOpened(InternalFrameEvent e) {
0755: }
0756:
0757: public void internalFrameClosed(InternalFrameEvent e) {
0758: }
0759:
0760: public void internalFrameIconified(InternalFrameEvent e) {
0761: }
0762:
0763: public void internalFrameDeiconified(InternalFrameEvent e) {
0764: }
0765:
0766: public void internalFrameActivated(InternalFrameEvent e) {
0767: }
0768:
0769: public void internalFrameDeactivated(InternalFrameEvent e) {
0770: }
0771:
0772: private static void usage() {
0773: System.err.println(Resources.getText("zz usage text",
0774: "jconsole"));
0775: }
0776:
0777: private static void mainInit(final List<String> urls,
0778: final List<String> hostNames, final List<Integer> ports,
0779: final List<LocalVirtualMachine> vmids,
0780: final ProxyClient proxyClient, final boolean noTile,
0781: final boolean hotspot) {
0782:
0783: // Always create Swing GUI on the Event Dispatching Thread
0784: SwingUtilities.invokeLater(new Runnable() {
0785: public void run() {
0786: JConsole jConsole = new JConsole(hotspot);
0787:
0788: // Center the window on screen, taking into account screen
0789: // size and insets.
0790: Toolkit toolkit = Toolkit.getDefaultToolkit();
0791: GraphicsConfiguration gc = jConsole
0792: .getGraphicsConfiguration();
0793: Dimension scrSize = toolkit.getScreenSize();
0794: Insets scrInsets = toolkit.getScreenInsets(gc);
0795: Rectangle scrBounds = new Rectangle(scrInsets.left,
0796: scrInsets.top, scrSize.width - scrInsets.left
0797: - scrInsets.right, scrSize.height
0798: - scrInsets.top - scrInsets.bottom);
0799: int w = Math.min(900, scrBounds.width);
0800: int h = Math.min(750, scrBounds.height);
0801: jConsole.setBounds(scrBounds.x + (scrBounds.width - w)
0802: / 2, scrBounds.y + (scrBounds.height - h) / 2,
0803: w, h);
0804:
0805: jConsole.setVisible(true);
0806: jConsole.createMDI();
0807:
0808: for (int i = 0; i < hostNames.size(); i++) {
0809: jConsole.addHost(hostNames.get(i), ports.get(i),
0810: null, null,
0811: (i == hostNames.size() - 1) ? !noTile
0812: : false);
0813: }
0814:
0815: for (int i = 0; i < urls.size(); i++) {
0816: jConsole.addUrl(urls.get(i), null, null, (i == urls
0817: .size() - 1) ? !noTile : false);
0818: }
0819:
0820: for (int i = 0; i < vmids.size(); i++) {
0821: jConsole.addVmid(vmids.get(i),
0822: (i == vmids.size() - 1) ? !noTile : false);
0823: }
0824:
0825: if (vmids.size() == 0 && hostNames.size() == 0
0826: && urls.size() == 0) {
0827: jConsole.showConnectDialog(null, null, 0, null,
0828: null, null);
0829: }
0830: }
0831: });
0832: }
0833:
0834: public static void main(String[] args) {
0835: boolean noTile = false, hotspot = false;
0836: int argIndex = 0;
0837: ProxyClient proxyClient = null;
0838:
0839: if (System.getProperty("jconsole.showOutputViewer") != null) {
0840: OutputViewer.init();
0841: }
0842:
0843: while (args.length - argIndex > 0
0844: && args[argIndex].startsWith("-")) {
0845: String arg = args[argIndex++];
0846: if (arg.equals("-h") || arg.equals("-help")
0847: || arg.equals("-?")) {
0848:
0849: usage();
0850: return;
0851: } else if (arg.startsWith("-interval=")) {
0852: try {
0853: updateInterval = Integer
0854: .parseInt(arg.substring(10)) * 1000;
0855: } catch (NumberFormatException ex) {
0856: usage();
0857: return;
0858: }
0859: } else if (arg.equals("-pluginpath")) {
0860: if (argIndex < args.length
0861: && !args[argIndex].startsWith("-")) {
0862: pluginPath = args[argIndex++];
0863: } else {
0864: // Invalid argument
0865: usage();
0866: return;
0867: }
0868: } else if (arg.equals("-notile")) {
0869: noTile = true;
0870: } else if (arg.equals("-version")) {
0871: Version.print(System.err);
0872: return;
0873: } else if (arg.equals("-debug")) {
0874: debug = true;
0875: } else if (arg.equals("-fullversion")) {
0876: Version.printFullVersion(System.err);
0877: return;
0878: } else {
0879: // Unknown switch
0880: usage();
0881: return;
0882: }
0883: }
0884:
0885: if (System.getProperty("jconsole.showUnsupported") != null) {
0886: hotspot = true;
0887: }
0888:
0889: List<String> urls = new ArrayList<String>();
0890: List<String> hostNames = new ArrayList<String>();
0891: List<Integer> ports = new ArrayList<Integer>();
0892: List<LocalVirtualMachine> vms = new ArrayList<LocalVirtualMachine>();
0893:
0894: for (int i = argIndex; i < args.length; i++) {
0895: String arg = args[i];
0896: if (isValidRemoteString(arg)) {
0897: if (arg.startsWith(ROOT_URL)) {
0898: urls.add(arg);
0899: } else if (arg.matches(".*:[0-9]*")) {
0900: int p = arg.lastIndexOf(':');
0901: hostNames.add(arg.substring(0, p));
0902: try {
0903: ports.add(Integer
0904: .parseInt(arg.substring(p + 1)));
0905: } catch (NumberFormatException ex) {
0906: usage();
0907: return;
0908: }
0909: }
0910: } else {
0911: if (!isLocalAttachAvailable()) {
0912: System.err
0913: .println("Local process monitoring is not supported");
0914: return;
0915: }
0916: try {
0917: int vmid = Integer.parseInt(arg);
0918: LocalVirtualMachine lvm = LocalVirtualMachine
0919: .getLocalVirtualMachine(vmid);
0920: if (lvm == null) {
0921: System.err
0922: .println("Invalid process id:" + vmid);
0923: return;
0924: }
0925: vms.add(lvm);
0926: } catch (NumberFormatException ex) {
0927: usage();
0928: return;
0929: }
0930: }
0931: }
0932:
0933: mainInit(urls, hostNames, ports, vms, proxyClient, noTile,
0934: hotspot);
0935: }
0936:
0937: public static boolean isDebug() {
0938: return debug;
0939: }
0940:
0941: private static void dbgStackTrace(Exception ex) {
0942: if (debug) {
0943: ex.printStackTrace();
0944: }
0945: }
0946:
0947: private static final boolean localAttachmentSupported;
0948: static {
0949: boolean supported;
0950: try {
0951: Class.forName("com.sun.tools.attach.VirtualMachine");
0952: Class.forName("sun.management.ConnectorAddressLink");
0953: supported = true;
0954: } catch (NoClassDefFoundError x) {
0955: supported = false;
0956: } catch (ClassNotFoundException x) {
0957: supported = false;
0958: }
0959: localAttachmentSupported = supported;
0960: }
0961:
0962: public static boolean isLocalAttachAvailable() {
0963: return localAttachmentSupported;
0964: }
0965:
0966: private static ServiceLoader<JConsolePlugin> pluginService = null;
0967:
0968: // Return a list of newly instantiated JConsolePlugin objects
0969: static synchronized List<JConsolePlugin> getPlugins() {
0970: if (pluginService == null) {
0971: // First time loading and initializing the plugins
0972: initPluginService(pluginPath);
0973: } else {
0974: // reload the plugin so that new instances will be created
0975: pluginService.reload();
0976: }
0977:
0978: List<JConsolePlugin> plugins = new ArrayList<JConsolePlugin>();
0979: for (JConsolePlugin p : pluginService) {
0980: plugins.add(p);
0981: }
0982: return plugins;
0983: }
0984:
0985: private static void initPluginService(String pluginPath) {
0986: if (pluginPath.length() > 0) {
0987: try {
0988: ClassLoader pluginCL = new URLClassLoader(
0989: pathToURLs(pluginPath));
0990: ServiceLoader<JConsolePlugin> plugins = ServiceLoader
0991: .load(JConsolePlugin.class, pluginCL);
0992: // validate all plugins
0993: for (JConsolePlugin p : plugins) {
0994: if (isDebug()) {
0995: System.out.println("Plugin " + p.getClass()
0996: + " loaded.");
0997: }
0998: }
0999: pluginService = plugins;
1000: } catch (ServiceConfigurationError e) {
1001: // Error occurs during initialization of plugin
1002: System.out.println(Resources.getText(
1003: "Fail to load plugin", e.getMessage()));
1004: } catch (MalformedURLException e) {
1005: if (JConsole.isDebug()) {
1006: e.printStackTrace();
1007: }
1008: System.out.println(Resources.getText(
1009: "Invalid plugin path", e.getMessage()));
1010: }
1011: }
1012:
1013: if (pluginService == null) {
1014: initEmptyPlugin();
1015: }
1016: }
1017:
1018: private static void initEmptyPlugin() {
1019: ClassLoader pluginCL = new URLClassLoader(new URL[0]);
1020: pluginService = ServiceLoader.load(JConsolePlugin.class,
1021: pluginCL);
1022: }
1023:
1024: /**
1025: * Utility method for converting a search path string to an array
1026: * of directory and JAR file URLs.
1027: *
1028: * @param path the search path string
1029: * @return the resulting array of directory and JAR file URLs
1030: */
1031: private static URL[] pathToURLs(String path)
1032: throws MalformedURLException {
1033: String[] names = path.split(File.pathSeparator);
1034: URL[] urls = new URL[names.length];
1035: int count = 0;
1036: for (String f : names) {
1037: URL url = fileToURL(new File(f));
1038: urls[count++] = url;
1039: }
1040: return urls;
1041: }
1042:
1043: /**
1044: * Returns the directory or JAR file URL corresponding to the specified
1045: * local file name.
1046: *
1047: * @param file the File object
1048: * @return the resulting directory or JAR file URL, or null if unknown
1049: */
1050: private static URL fileToURL(File file)
1051: throws MalformedURLException {
1052: String name;
1053: try {
1054: name = file.getCanonicalPath();
1055: } catch (IOException e) {
1056: name = file.getAbsolutePath();
1057: }
1058: name = name.replace(File.separatorChar, '/');
1059: if (!name.startsWith("/")) {
1060: name = "/" + name;
1061: }
1062: // If the file does not exist, then assume that it's a directory
1063: if (!file.isFile()) {
1064: name = name + "/";
1065: }
1066: return new URL("file", "", name);
1067: }
1068:
1069: private static class FixedJRootPane extends JRootPane {
1070: public void updateUI() {
1071: updateLafValues();
1072: super .updateUI();
1073: }
1074:
1075: /**
1076: * The revalidate method seems to be the only one that gets
1077: * called whenever there is a change of L&F or change of theme
1078: * in Windows L&F and GTK L&F.
1079: */
1080: @Override
1081: public void revalidate() {
1082: // Workaround for Swing bug where the titledborder in both
1083: // GTK and Windows L&F's use calculated colors instead of
1084: // the highlight/shadow colors from the theme.
1085: //
1086: // Putting null removes any previous override and causes a
1087: // fallback to the current L&F's value.
1088: UIManager.put("TitledBorder.border", null);
1089: Border border = UIManager.getBorder("TitledBorder.border");
1090: if (border instanceof BorderUIResource.EtchedBorderUIResource) {
1091: Color highlight = UIManager
1092: .getColor("ToolBar.highlight");
1093: Color shadow = UIManager.getColor("ToolBar.shadow");
1094: border = new BorderUIResource.EtchedBorderUIResource(
1095: highlight, shadow);
1096: UIManager.put("TitledBorder.border", border);
1097: }
1098:
1099: if (IS_GTK) {
1100: // Workaround for Swing bug where the titledborder in
1101: // GTK L&F use hardcoded color and font for the title
1102: // instead of getting them from the theme.
1103: UIManager.put("TitledBorder.titleColor", UIManager
1104: .getColor("Label.foreground"));
1105: UIManager.put("TitledBorder.font", UIManager
1106: .getFont("Label.font"));
1107: }
1108: super.revalidate();
1109: }
1110: }
1111: }
|