0N/A/*
2362N/A * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.tools.jconsole;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.beans.*;
0N/Aimport java.lang.reflect.*;
0N/Aimport java.util.*;
0N/Aimport java.util.List;
0N/Aimport java.util.Timer;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.plaf.*;
0N/A
5335N/A
0N/Aimport com.sun.tools.jconsole.JConsolePlugin;
0N/Aimport com.sun.tools.jconsole.JConsoleContext;
0N/A
0N/Aimport static sun.tools.jconsole.ProxyClient.*;
0N/A
0N/A@SuppressWarnings("serial")
0N/Apublic class VMPanel extends JTabbedPane implements PropertyChangeListener {
32N/A
0N/A private ProxyClient proxyClient;
0N/A private Timer timer;
0N/A private int updateInterval;
0N/A private String hostName;
0N/A private int port;
0N/A private String userName;
0N/A private String password;
0N/A private String url;
0N/A private VMInternalFrame vmIF = null;
0N/A private static ArrayList<TabInfo> tabInfos = new ArrayList<TabInfo>();
0N/A private boolean wasConnected = false;
6282N/A private boolean shouldUseSSL = true;
6107N/A private boolean userDisconnected = false;
0N/A
0N/A // The everConnected flag keeps track of whether the window can be
0N/A // closed if the user clicks Cancel after a failed connection attempt.
0N/A //
0N/A private boolean everConnected = false;
0N/A
0N/A // The initialUpdate flag is used to enable/disable tabs each time
0N/A // a connect or reconnect takes place. This flag avoids having to
0N/A // enable/disable tabs on each update call.
0N/A //
0N/A private boolean initialUpdate = true;
0N/A
0N/A // Each VMPanel has its own instance of the JConsolePlugin
0N/A // A map of JConsolePlugin to the previous SwingWorker
32N/A private Map<JConsolePlugin, SwingWorker<?, ?>> plugins = null;
0N/A private boolean pluginTabsAdded = false;
0N/A
0N/A // Update these only on the EDT
0N/A private JOptionPane optionPane;
0N/A private JProgressBar progressBar;
0N/A private long time0;
0N/A
0N/A static {
0N/A tabInfos.add(new TabInfo(OverviewTab.class, OverviewTab.getTabName(), true));
32N/A tabInfos.add(new TabInfo(MemoryTab.class, MemoryTab.getTabName(), true));
32N/A tabInfos.add(new TabInfo(ThreadTab.class, ThreadTab.getTabName(), true));
32N/A tabInfos.add(new TabInfo(ClassTab.class, ClassTab.getTabName(), true));
0N/A tabInfos.add(new TabInfo(SummaryTab.class, SummaryTab.getTabName(), true));
32N/A tabInfos.add(new TabInfo(MBeansTab.class, MBeansTab.getTabName(), true));
0N/A }
0N/A
0N/A public static TabInfo[] getTabInfos() {
0N/A return tabInfos.toArray(new TabInfo[tabInfos.size()]);
0N/A }
0N/A
0N/A VMPanel(ProxyClient proxyClient, int updateInterval) {
0N/A this.proxyClient = proxyClient;
0N/A this.updateInterval = updateInterval;
0N/A this.hostName = proxyClient.getHostName();
32N/A this.port = proxyClient.getPort();
0N/A this.userName = proxyClient.getUserName();
0N/A this.password = proxyClient.getPassword();
0N/A this.url = proxyClient.getUrl();
0N/A
0N/A for (TabInfo tabInfo : tabInfos) {
0N/A if (tabInfo.tabVisible) {
0N/A addTab(tabInfo);
0N/A }
0N/A }
0N/A
32N/A plugins = new LinkedHashMap<JConsolePlugin, SwingWorker<?, ?>>();
0N/A for (JConsolePlugin p : JConsole.getPlugins()) {
0N/A p.setContext(proxyClient);
0N/A plugins.put(p, null);
0N/A }
0N/A
0N/A Utilities.updateTransparency(this);
0N/A
0N/A ToolTipManager.sharedInstance().registerComponent(this);
0N/A
0N/A // Start listening to connection state events
0N/A //
0N/A proxyClient.addPropertyChangeListener(this);
0N/A
0N/A addMouseListener(new MouseAdapter() {
32N/A
0N/A public void mouseClicked(MouseEvent e) {
32N/A if (connectedIconBounds != null && (e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0 && connectedIconBounds.contains(e.getPoint())) {
0N/A
0N/A if (isConnected()) {
6107N/A userDisconnected = true;
0N/A disconnect();
0N/A wasConnected = false;
0N/A } else {
0N/A connect();
0N/A }
0N/A repaint();
0N/A }
0N/A }
0N/A });
0N/A
0N/A }
0N/A private static Icon connectedIcon16 =
32N/A new ImageIcon(VMPanel.class.getResource("resources/connected16.png"));
0N/A private static Icon connectedIcon24 =
32N/A new ImageIcon(VMPanel.class.getResource("resources/connected24.png"));
0N/A private static Icon disconnectedIcon16 =
32N/A new ImageIcon(VMPanel.class.getResource("resources/disconnected16.png"));
0N/A private static Icon disconnectedIcon24 =
32N/A new ImageIcon(VMPanel.class.getResource("resources/disconnected24.png"));
0N/A private Rectangle connectedIconBounds;
0N/A
0N/A // Override to increase right inset for tab area,
0N/A // in order to reserve space for the connect toggle.
0N/A public void setUI(TabbedPaneUI ui) {
32N/A Insets insets = (Insets) UIManager.getLookAndFeelDefaults().get("TabbedPane.tabAreaInsets");
32N/A insets = (Insets) insets.clone();
0N/A insets.right += connectedIcon24.getIconWidth() + 8;
0N/A UIManager.put("TabbedPane.tabAreaInsets", insets);
0N/A super.setUI(ui);
0N/A }
0N/A
0N/A // Override to paint the connect toggle
0N/A protected void paintComponent(Graphics g) {
0N/A super.paintComponent(g);
0N/A
0N/A Icon icon;
0N/A Component c0 = getComponent(0);
0N/A if (c0 != null && c0.getY() > 24) {
0N/A icon = isConnected() ? connectedIcon24 : disconnectedIcon24;
0N/A } else {
0N/A icon = isConnected() ? connectedIcon16 : disconnectedIcon16;
0N/A }
0N/A Insets insets = getInsets();
0N/A int x = getWidth() - insets.right - icon.getIconWidth() - 4;
0N/A int y = insets.top;
0N/A if (c0 != null) {
0N/A y = (c0.getY() - icon.getIconHeight()) / 2;
0N/A }
0N/A icon.paintIcon(this, g, x, y);
0N/A connectedIconBounds = new Rectangle(x, y, icon.getIconWidth(), icon.getIconHeight());
0N/A }
0N/A
0N/A public String getToolTipText(MouseEvent event) {
0N/A if (connectedIconBounds.contains(event.getPoint())) {
0N/A if (isConnected()) {
5335N/A return Messages.CONNECTED_PUNCTUATION_CLICK_TO_DISCONNECT_;
0N/A } else {
5335N/A return Messages.DISCONNECTED_PUNCTUATION_CLICK_TO_CONNECT_;
0N/A }
0N/A } else {
0N/A return super.getToolTipText(event);
0N/A }
0N/A }
0N/A
0N/A private synchronized void addTab(TabInfo tabInfo) {
0N/A Tab tab = instantiate(tabInfo);
0N/A if (tab != null) {
0N/A addTab(tabInfo.name, tab);
0N/A } else {
0N/A tabInfo.tabVisible = false;
0N/A }
0N/A }
0N/A
0N/A private synchronized void insertTab(TabInfo tabInfo, int index) {
0N/A Tab tab = instantiate(tabInfo);
0N/A if (tab != null) {
0N/A insertTab(tabInfo.name, null, tab, null, index);
0N/A } else {
0N/A tabInfo.tabVisible = false;
0N/A }
0N/A }
0N/A
0N/A public synchronized void removeTabAt(int index) {
0N/A super.removeTabAt(index);
0N/A }
0N/A
0N/A private Tab instantiate(TabInfo tabInfo) {
0N/A try {
5335N/A Constructor<?> con = tabInfo.tabClass.getConstructor(VMPanel.class);
32N/A return (Tab) con.newInstance(this);
0N/A } catch (Exception ex) {
0N/A System.err.println(ex);
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A boolean isConnected() {
0N/A return proxyClient.isConnected();
0N/A }
0N/A
0N/A public int getUpdateInterval() {
0N/A return updateInterval;
0N/A }
0N/A
0N/A /**
0N/A * WARNING NEVER CALL THIS METHOD TO MAKE JMX REQUEST
0N/A * IF assertThread == false.
0N/A * DISPATCHER THREAD IS NOT ASSERTED.
0N/A * IT IS USED TO MAKE SOME LOCAL MANIPULATIONS.
0N/A */
0N/A ProxyClient getProxyClient(boolean assertThread) {
32N/A if (assertThread) {
0N/A return getProxyClient();
32N/A } else {
0N/A return proxyClient;
32N/A }
0N/A }
0N/A
0N/A public ProxyClient getProxyClient() {
0N/A String threadClass = Thread.currentThread().getClass().getName();
0N/A if (threadClass.equals("java.awt.EventDispatchThread")) {
0N/A String msg = "Calling VMPanel.getProxyClient() from the Event Dispatch Thread!";
0N/A new RuntimeException(msg).printStackTrace();
0N/A System.exit(1);
0N/A }
0N/A return proxyClient;
0N/A }
0N/A
0N/A public void cleanUp() {
0N/A //proxyClient.disconnect();
0N/A for (Tab tab : getTabs()) {
0N/A tab.dispose();
0N/A }
0N/A for (JConsolePlugin p : plugins.keySet()) {
0N/A p.dispose();
0N/A }
0N/A // Cancel pending update tasks
0N/A //
0N/A if (timer != null) {
0N/A timer.cancel();
0N/A }
0N/A // Stop listening to connection state events
0N/A //
0N/A proxyClient.removePropertyChangeListener(this);
0N/A }
0N/A
0N/A // Call on EDT
0N/A public void connect() {
0N/A if (isConnected()) {
0N/A // create plugin tabs if not done
0N/A createPluginTabs();
0N/A // Notify tabs
0N/A fireConnectedChange(true);
0N/A // Enable/disable tabs on initial update
0N/A initialUpdate = true;
0N/A // Start/Restart update timer on connect/reconnect
0N/A startUpdateTimer();
0N/A } else {
0N/A new Thread("VMPanel.connect") {
32N/A
0N/A public void run() {
6282N/A proxyClient.connect(shouldUseSSL);
0N/A }
0N/A }.start();
0N/A }
0N/A }
0N/A
0N/A // Call on EDT
0N/A public void disconnect() {
0N/A proxyClient.disconnect();
0N/A updateFrameTitle();
0N/A }
0N/A
0N/A // Called on EDT
0N/A public void propertyChange(PropertyChangeEvent ev) {
0N/A String prop = ev.getPropertyName();
0N/A
0N/A if (prop == CONNECTION_STATE_PROPERTY) {
32N/A ConnectionState oldState = (ConnectionState) ev.getOldValue();
32N/A ConnectionState newState = (ConnectionState) ev.getNewValue();
0N/A switch (newState) {
32N/A case CONNECTING:
32N/A onConnecting();
32N/A break;
0N/A
32N/A case CONNECTED:
32N/A if (progressBar != null) {
32N/A progressBar.setIndeterminate(false);
32N/A progressBar.setValue(100);
32N/A }
32N/A closeOptionPane();
32N/A updateFrameTitle();
32N/A // create tabs if not done
32N/A createPluginTabs();
32N/A repaint();
32N/A // Notify tabs
32N/A fireConnectedChange(true);
32N/A // Enable/disable tabs on initial update
32N/A initialUpdate = true;
32N/A // Start/Restart update timer on connect/reconnect
32N/A startUpdateTimer();
32N/A break;
0N/A
32N/A case DISCONNECTED:
32N/A if (progressBar != null) {
32N/A progressBar.setIndeterminate(false);
32N/A progressBar.setValue(0);
32N/A closeOptionPane();
32N/A }
32N/A vmPanelDied();
32N/A if (oldState == ConnectionState.CONNECTED) {
32N/A // Notify tabs
32N/A fireConnectedChange(false);
32N/A }
32N/A break;
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Called on EDT
0N/A private void onConnecting() {
0N/A time0 = System.currentTimeMillis();
0N/A
5335N/A SwingUtilities.getWindowAncestor(this);
0N/A
0N/A String connectionName = getConnectionName();
0N/A progressBar = new JProgressBar();
0N/A progressBar.setIndeterminate(true);
0N/A JPanel progressPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
0N/A progressPanel.add(progressBar);
0N/A
0N/A Object[] message = {
5335N/A "<html><h3>" + Resources.format(Messages.CONNECTING_TO1, connectionName) + "</h3></html>",
0N/A progressPanel,
5335N/A "<html><b>" + Resources.format(Messages.CONNECTING_TO2, connectionName) + "</b></html>"
0N/A };
0N/A
0N/A optionPane =
32N/A SheetDialog.showOptionDialog(this,
32N/A message,
32N/A JOptionPane.DEFAULT_OPTION,
32N/A JOptionPane.INFORMATION_MESSAGE, null,
5335N/A new String[]{Messages.CANCEL},
32N/A 0);
0N/A
0N/A
0N/A }
0N/A
0N/A // Called on EDT
0N/A private void closeOptionPane() {
0N/A if (optionPane != null) {
0N/A new Thread("VMPanel.sleeper") {
0N/A public void run() {
0N/A long elapsed = System.currentTimeMillis() - time0;
0N/A if (elapsed < 2000) {
0N/A try {
0N/A sleep(2000 - elapsed);
0N/A } catch (InterruptedException ex) {
32N/A // Ignore
0N/A }
0N/A }
0N/A SwingUtilities.invokeLater(new Runnable() {
32N/A
0N/A public void run() {
0N/A optionPane.setVisible(false);
0N/A progressBar = null;
0N/A }
0N/A });
0N/A }
0N/A }.start();
0N/A }
0N/A }
0N/A
0N/A void updateFrameTitle() {
0N/A VMInternalFrame vmIF = getFrame();
0N/A if (vmIF != null) {
0N/A String displayName = getDisplayName();
0N/A if (!proxyClient.isConnected()) {
5335N/A displayName = Resources.format(Messages.CONNECTION_NAME__DISCONNECTED_, displayName);
0N/A }
0N/A vmIF.setTitle(displayName);
0N/A }
0N/A }
0N/A
0N/A private VMInternalFrame getFrame() {
0N/A if (vmIF == null) {
32N/A vmIF = (VMInternalFrame) SwingUtilities.getAncestorOfClass(VMInternalFrame.class,
32N/A this);
0N/A }
0N/A return vmIF;
0N/A }
0N/A
0N/A // TODO: this method is not needed when all JConsole tabs
0N/A // are migrated to use the new JConsolePlugin API.
0N/A //
0N/A // A thread safe clone of all JConsole tabs
0N/A synchronized List<Tab> getTabs() {
0N/A ArrayList<Tab> list = new ArrayList<Tab>();
0N/A int n = getTabCount();
0N/A for (int i = 0; i < n; i++) {
0N/A Component c = getComponentAt(i);
0N/A if (c instanceof Tab) {
0N/A list.add((Tab) c);
0N/A }
0N/A }
0N/A return list;
0N/A }
0N/A
0N/A private void startUpdateTimer() {
0N/A if (timer != null) {
0N/A timer.cancel();
0N/A }
0N/A TimerTask timerTask = new TimerTask() {
32N/A
0N/A public void run() {
0N/A update();
0N/A }
0N/A };
32N/A String timerName = "Timer-" + getConnectionName();
0N/A timer = new Timer(timerName, true);
0N/A timer.schedule(timerTask, 0, updateInterval);
0N/A }
0N/A
0N/A // Call on EDT
0N/A private void vmPanelDied() {
0N/A disconnect();
0N/A
6107N/A if (userDisconnected) {
6107N/A userDisconnected = false;
6107N/A return;
6107N/A }
0N/A
0N/A JOptionPane optionPane;
0N/A String msgTitle, msgExplanation, buttonStr;
0N/A
0N/A if (wasConnected) {
0N/A wasConnected = false;
5335N/A msgTitle = Messages.CONNECTION_LOST1;
5335N/A msgExplanation = Resources.format(Messages.CONNECTING_TO2, getConnectionName());
5335N/A buttonStr = Messages.RECONNECT;
6282N/A } else if (shouldUseSSL) {
6407N/A msgTitle = Messages.CONNECTION_INSECURE1;
6407N/A msgExplanation = Resources.format(Messages.CONNECTION_INSECURE2, getConnectionName());
6407N/A buttonStr = Messages.INSECURE;
0N/A } else {
6407N/A msgTitle = Messages.CONNECTION_FAILED1;
5335N/A msgExplanation = Resources.format(Messages.CONNECTION_FAILED2, getConnectionName());
5335N/A buttonStr = Messages.CONNECT;
0N/A }
0N/A
0N/A optionPane =
32N/A SheetDialog.showOptionDialog(this,
32N/A "<html><h3>" + msgTitle + "</h3>" +
32N/A "<b>" + msgExplanation + "</b>",
32N/A JOptionPane.DEFAULT_OPTION,
32N/A JOptionPane.WARNING_MESSAGE, null,
5335N/A new String[]{buttonStr, Messages.CANCEL},
32N/A 0);
0N/A
0N/A optionPane.addPropertyChangeListener(new PropertyChangeListener() {
32N/A
0N/A public void propertyChange(PropertyChangeEvent event) {
0N/A if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {
0N/A Object value = event.getNewValue();
0N/A
5335N/A if (value == Messages.RECONNECT || value == Messages.CONNECT) {
0N/A connect();
6407N/A } else if (value == Messages.INSECURE) {
6282N/A shouldUseSSL = false;
6282N/A connect();
0N/A } else if (!everConnected) {
0N/A try {
0N/A getFrame().setClosed(true);
0N/A } catch (PropertyVetoException ex) {
32N/A // Should not happen, but can be ignored.
0N/A }
0N/A }
0N/A }
0N/A }
0N/A });
0N/A }
0N/A
0N/A // Note: This method is called on a TimerTask thread. Any GUI manipulation
0N/A // must be performed with invokeLater() or invokeAndWait().
0N/A private Object lockObject = new Object();
32N/A
0N/A private void update() {
32N/A synchronized (lockObject) {
0N/A if (!isConnected()) {
0N/A if (wasConnected) {
0N/A EventQueue.invokeLater(new Runnable() {
32N/A
0N/A public void run() {
0N/A vmPanelDied();
0N/A }
0N/A });
0N/A }
0N/A wasConnected = false;
0N/A return;
0N/A } else {
0N/A wasConnected = true;
0N/A everConnected = true;
0N/A }
0N/A proxyClient.flush();
0N/A List<Tab> tabs = getTabs();
0N/A final int n = tabs.size();
0N/A for (int i = 0; i < n; i++) {
0N/A final int index = i;
0N/A try {
0N/A if (!proxyClient.isDead()) {
0N/A // Update tab
0N/A //
0N/A tabs.get(index).update();
0N/A // Enable tab on initial update
0N/A //
0N/A if (initialUpdate) {
0N/A EventQueue.invokeLater(new Runnable() {
32N/A
0N/A public void run() {
0N/A setEnabledAt(index, true);
0N/A }
0N/A });
0N/A }
0N/A }
0N/A } catch (Exception e) {
0N/A // Disable tab on initial update
0N/A //
0N/A if (initialUpdate) {
0N/A EventQueue.invokeLater(new Runnable() {
0N/A public void run() {
0N/A setEnabledAt(index, false);
0N/A }
0N/A });
0N/A }
0N/A }
0N/A }
0N/A
0N/A // plugin GUI update
0N/A for (JConsolePlugin p : plugins.keySet()) {
32N/A SwingWorker<?, ?> sw = p.newSwingWorker();
32N/A SwingWorker<?, ?> prevSW = plugins.get(p);
0N/A // schedule SwingWorker to run only if the previous
0N/A // SwingWorker has finished its task and it hasn't started.
0N/A if (prevSW == null || prevSW.isDone()) {
0N/A if (sw == null || sw.getState() == SwingWorker.StateValue.PENDING) {
0N/A plugins.put(p, sw);
0N/A if (sw != null) {
0N/A sw.execute();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
32N/A // Set the first enabled tab in the tab's list
0N/A // as the selected tab on initial update
0N/A //
0N/A if (initialUpdate) {
0N/A EventQueue.invokeLater(new Runnable() {
0N/A public void run() {
0N/A // Select first enabled tab if current tab isn't.
0N/A int index = getSelectedIndex();
0N/A if (index < 0 || !isEnabledAt(index)) {
0N/A for (int i = 0; i < n; i++) {
0N/A if (isEnabledAt(i)) {
0N/A setSelectedIndex(i);
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A });
0N/A initialUpdate = false;
0N/A }
0N/A }
0N/A }
0N/A
0N/A public String getHostName() {
0N/A return hostName;
0N/A }
0N/A
0N/A public int getPort() {
0N/A return port;
0N/A }
0N/A
0N/A public String getUserName() {
0N/A return userName;
0N/A }
0N/A
0N/A public String getUrl() {
0N/A return url;
0N/A }
0N/A
0N/A public String getPassword() {
0N/A return password;
0N/A }
0N/A
0N/A public String getConnectionName() {
0N/A return proxyClient.connectionName();
0N/A }
0N/A
0N/A public String getDisplayName() {
0N/A return proxyClient.getDisplayName();
0N/A }
0N/A
0N/A static class TabInfo {
32N/A
0N/A Class<? extends Tab> tabClass;
0N/A String name;
0N/A boolean tabVisible;
0N/A
0N/A TabInfo(Class<? extends Tab> tabClass, String name, boolean tabVisible) {
0N/A this.tabClass = tabClass;
0N/A this.name = name;
0N/A this.tabVisible = tabVisible;
0N/A }
0N/A }
0N/A
0N/A private void createPluginTabs() {
0N/A // add plugin tabs if not done
0N/A if (!pluginTabsAdded) {
0N/A for (JConsolePlugin p : plugins.keySet()) {
0N/A Map<String, JPanel> tabs = p.getTabs();
0N/A for (Map.Entry<String, JPanel> e : tabs.entrySet()) {
0N/A addTab(e.getKey(), e.getValue());
0N/A }
0N/A }
0N/A pluginTabsAdded = true;
0N/A }
0N/A }
0N/A
0N/A private void fireConnectedChange(boolean connected) {
0N/A for (Tab tab : getTabs()) {
0N/A tab.firePropertyChange(JConsoleContext.CONNECTION_STATE_PROPERTY, !connected, connected);
0N/A }
0N/A }
0N/A}