blob: 10a01e8df650ccedcb59caaf2bc68b47f2f9d614 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.tools.jconsole;
27
28import java.awt.*;
29import java.awt.event.*;
30import java.beans.*;
31import java.io.*;
32import java.lang.reflect.InvocationTargetException;
33import java.net.*;
34import java.util.*;
35import java.util.List;
36
37import javax.swing.*;
38import javax.swing.border.*;
39import javax.swing.event.*;
40import javax.swing.plaf.*;
41import javax.management.remote.JMXServiceURL;
42import javax.management.remote.JMXConnector;
43import javax.security.auth.login.FailedLoginException;
44import javax.net.ssl.SSLHandshakeException;
45
46import com.sun.tools.jconsole.JConsolePlugin;
47
48import sun.net.util.IPAddressUtil;
49
50import static sun.tools.jconsole.Resources.*;
51import static sun.tools.jconsole.Utilities.*;
52
53@SuppressWarnings("serial")
54public 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}