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