Path: blob/master/src/jdk.jconsole/share/classes/sun/tools/jconsole/VMPanel.java
40948 views
/*1* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tools.jconsole;2627import java.awt.*;28import java.awt.event.*;29import java.beans.*;30import java.lang.reflect.*;31import java.util.*;32import java.util.List;33import java.util.Timer;34import javax.swing.*;35import javax.swing.plaf.*;363738import com.sun.tools.jconsole.JConsolePlugin;39import com.sun.tools.jconsole.JConsoleContext;4041import static sun.tools.jconsole.ProxyClient.*;4243@SuppressWarnings("serial")44public class VMPanel extends JTabbedPane implements PropertyChangeListener {4546private ProxyClient proxyClient;47private Timer timer;48private int updateInterval;49private String hostName;50private int port;51private String userName;52private String password;53private String url;54private VMInternalFrame vmIF = null;55private static ArrayList<TabInfo> tabInfos = new ArrayList<TabInfo>();56private boolean wasConnected = false;57private boolean userDisconnected = false;58private boolean shouldUseSSL = true;5960// The everConnected flag keeps track of whether the window can be61// closed if the user clicks Cancel after a failed connection attempt.62//63private boolean everConnected = false;6465// The initialUpdate flag is used to enable/disable tabs each time66// a connect or reconnect takes place. This flag avoids having to67// enable/disable tabs on each update call.68//69private boolean initialUpdate = true;7071// Each VMPanel has its own instance of the JConsolePlugin72// A map of JConsolePlugin to the previous SwingWorker73private Map<ExceptionSafePlugin, SwingWorker<?, ?>> plugins = null;74private boolean pluginTabsAdded = false;7576// Update these only on the EDT77private JOptionPane optionPane;78private JProgressBar progressBar;79private long time0;8081static {82tabInfos.add(new TabInfo(OverviewTab.class, OverviewTab.getTabName(), true));83tabInfos.add(new TabInfo(MemoryTab.class, MemoryTab.getTabName(), true));84tabInfos.add(new TabInfo(ThreadTab.class, ThreadTab.getTabName(), true));85tabInfos.add(new TabInfo(ClassTab.class, ClassTab.getTabName(), true));86tabInfos.add(new TabInfo(SummaryTab.class, SummaryTab.getTabName(), true));87tabInfos.add(new TabInfo(MBeansTab.class, MBeansTab.getTabName(), true));88}8990public static TabInfo[] getTabInfos() {91return tabInfos.toArray(new TabInfo[tabInfos.size()]);92}9394VMPanel(ProxyClient proxyClient, int updateInterval) {95this.proxyClient = proxyClient;96this.updateInterval = updateInterval;97this.hostName = proxyClient.getHostName();98this.port = proxyClient.getPort();99this.userName = proxyClient.getUserName();100this.password = proxyClient.getPassword();101this.url = proxyClient.getUrl();102103for (TabInfo tabInfo : tabInfos) {104if (tabInfo.tabVisible) {105addTab(tabInfo);106}107}108109plugins = new LinkedHashMap<ExceptionSafePlugin, SwingWorker<?, ?>>();110for (JConsolePlugin p : JConsole.getPlugins()) {111p.setContext(proxyClient);112plugins.put(new ExceptionSafePlugin(p), null);113}114115Utilities.updateTransparency(this);116117ToolTipManager.sharedInstance().registerComponent(this);118119// Start listening to connection state events120//121proxyClient.addPropertyChangeListener(this);122123addMouseListener(new MouseAdapter() {124125public void mouseClicked(MouseEvent e) {126if (connectedIconBounds != null127&& (e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) != 0128&& connectedIconBounds.contains(e.getPoint())) {129130if (isConnected()) {131userDisconnected = true;132disconnect();133wasConnected = false;134} else {135connect();136}137repaint();138}139}140});141142}143private static Icon connectedIcon16 =144new ImageIcon(VMPanel.class.getResource("resources/connected16.png"));145private static Icon connectedIcon24 =146new ImageIcon(VMPanel.class.getResource("resources/connected24.png"));147private static Icon disconnectedIcon16 =148new ImageIcon(VMPanel.class.getResource("resources/disconnected16.png"));149private static Icon disconnectedIcon24 =150new ImageIcon(VMPanel.class.getResource("resources/disconnected24.png"));151private Rectangle connectedIconBounds;152153// Override to increase right inset for tab area,154// in order to reserve space for the connect toggle.155public void setUI(TabbedPaneUI ui) {156Insets insets = (Insets) UIManager.getLookAndFeelDefaults().get("TabbedPane.tabAreaInsets");157if (insets != null) {158insets = (Insets) insets.clone();159insets.right += connectedIcon24.getIconWidth() + 8;160UIManager.put("TabbedPane.tabAreaInsets", insets);161}162super.setUI(ui);163}164165// Override to paint the connect toggle166protected void paintComponent(Graphics g) {167super.paintComponent(g);168169Icon icon;170Component c0 = getComponent(0);171if (c0 != null && c0.getY() > 24) {172icon = isConnected() ? connectedIcon24 : disconnectedIcon24;173} else {174icon = isConnected() ? connectedIcon16 : disconnectedIcon16;175}176Insets insets = getInsets();177int x = getWidth() - insets.right - icon.getIconWidth() - 4;178int y = insets.top;179if (c0 != null) {180y = (c0.getY() - icon.getIconHeight()) / 2;181}182icon.paintIcon(this, g, x, y);183connectedIconBounds = new Rectangle(x, y, icon.getIconWidth(), icon.getIconHeight());184}185186public String getToolTipText(MouseEvent event) {187if (connectedIconBounds.contains(event.getPoint())) {188if (isConnected()) {189return Messages.CONNECTED_PUNCTUATION_CLICK_TO_DISCONNECT_;190} else {191return Messages.DISCONNECTED_PUNCTUATION_CLICK_TO_CONNECT_;192}193} else {194return super.getToolTipText(event);195}196}197198private synchronized void addTab(TabInfo tabInfo) {199Tab tab = instantiate(tabInfo);200if (tab != null) {201addTab(tabInfo.name, tab);202} else {203tabInfo.tabVisible = false;204}205}206207private synchronized void insertTab(TabInfo tabInfo, int index) {208Tab tab = instantiate(tabInfo);209if (tab != null) {210insertTab(tabInfo.name, null, tab, null, index);211} else {212tabInfo.tabVisible = false;213}214}215216public synchronized void removeTabAt(int index) {217super.removeTabAt(index);218}219220private Tab instantiate(TabInfo tabInfo) {221try {222Constructor<?> con = tabInfo.tabClass.getConstructor(VMPanel.class);223return (Tab) con.newInstance(this);224} catch (Exception ex) {225System.err.println(ex);226return null;227}228}229230boolean isConnected() {231return proxyClient.isConnected();232}233234public int getUpdateInterval() {235return updateInterval;236}237238/**239* WARNING NEVER CALL THIS METHOD TO MAKE JMX REQUEST240* IF assertThread == false.241* DISPATCHER THREAD IS NOT ASSERTED.242* IT IS USED TO MAKE SOME LOCAL MANIPULATIONS.243*/244ProxyClient getProxyClient(boolean assertThread) {245if (assertThread) {246return getProxyClient();247} else {248return proxyClient;249}250}251252public ProxyClient getProxyClient() {253String threadClass = Thread.currentThread().getClass().getName();254if (threadClass.equals("java.awt.EventDispatchThread")) {255String msg = "Calling VMPanel.getProxyClient() from the Event Dispatch Thread!";256new RuntimeException(msg).printStackTrace();257System.exit(1);258}259return proxyClient;260}261262public void cleanUp() {263//proxyClient.disconnect();264for (Tab tab : getTabs()) {265tab.dispose();266}267for (JConsolePlugin p : plugins.keySet()) {268p.dispose();269}270// Cancel pending update tasks271//272if (timer != null) {273timer.cancel();274}275// Stop listening to connection state events276//277proxyClient.removePropertyChangeListener(this);278}279280// Call on EDT281public void connect() {282if (isConnected()) {283// create plugin tabs if not done284createPluginTabs();285// Notify tabs286fireConnectedChange(true);287// Enable/disable tabs on initial update288initialUpdate = true;289// Start/Restart update timer on connect/reconnect290startUpdateTimer();291} else {292new Thread("VMPanel.connect") {293294public void run() {295proxyClient.connect(shouldUseSSL);296}297}.start();298}299}300301// Call on EDT302public void disconnect() {303proxyClient.disconnect();304updateFrameTitle();305}306307// Called on EDT308public void propertyChange(PropertyChangeEvent ev) {309String prop = ev.getPropertyName();310311if (prop == CONNECTION_STATE_PROPERTY) {312ConnectionState oldState = (ConnectionState) ev.getOldValue();313ConnectionState newState = (ConnectionState) ev.getNewValue();314switch (newState) {315case CONNECTING:316onConnecting();317break;318319case CONNECTED:320if (progressBar != null) {321progressBar.setIndeterminate(false);322progressBar.setValue(100);323}324closeOptionPane();325updateFrameTitle();326// create tabs if not done327createPluginTabs();328repaint();329// Notify tabs330fireConnectedChange(true);331// Enable/disable tabs on initial update332initialUpdate = true;333// Start/Restart update timer on connect/reconnect334startUpdateTimer();335break;336337case DISCONNECTED:338if (progressBar != null) {339progressBar.setIndeterminate(false);340progressBar.setValue(0);341closeOptionPane();342}343vmPanelDied();344if (oldState == ConnectionState.CONNECTED) {345// Notify tabs346fireConnectedChange(false);347}348break;349}350}351}352353// Called on EDT354private void onConnecting() {355time0 = System.currentTimeMillis();356357SwingUtilities.getWindowAncestor(this);358359String connectionName = getConnectionName();360progressBar = new JProgressBar();361progressBar.setIndeterminate(true);362JPanel progressPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));363progressPanel.add(progressBar);364365Object[] message = {366"<html><h3>" + Resources.format(Messages.CONNECTING_TO1, connectionName) + "</h3></html>",367progressPanel,368"<html><b>" + Resources.format(Messages.CONNECTING_TO2, connectionName) + "</b></html>"369};370371optionPane =372SheetDialog.showOptionDialog(this,373message,374JOptionPane.DEFAULT_OPTION,375JOptionPane.INFORMATION_MESSAGE, null,376new String[]{Messages.CANCEL},3770);378379380}381382// Called on EDT383private void closeOptionPane() {384if (optionPane != null) {385new Thread("VMPanel.sleeper") {386public void run() {387long elapsed = System.currentTimeMillis() - time0;388if (elapsed < 2000) {389try {390sleep(2000 - elapsed);391} catch (InterruptedException ex) {392// Ignore393}394}395SwingUtilities.invokeLater(new Runnable() {396397public void run() {398optionPane.setVisible(false);399progressBar = null;400}401});402}403}.start();404}405}406407void updateFrameTitle() {408VMInternalFrame vmIF = getFrame();409if (vmIF != null) {410String displayName = getDisplayName();411if (!proxyClient.isConnected()) {412displayName = Resources.format(Messages.CONNECTION_NAME__DISCONNECTED_, displayName);413}414vmIF.setTitle(displayName);415}416}417418private VMInternalFrame getFrame() {419if (vmIF == null) {420vmIF = (VMInternalFrame) SwingUtilities.getAncestorOfClass(VMInternalFrame.class,421this);422}423return vmIF;424}425426// TODO: this method is not needed when all JConsole tabs427// are migrated to use the new JConsolePlugin API.428//429// A thread safe clone of all JConsole tabs430synchronized List<Tab> getTabs() {431ArrayList<Tab> list = new ArrayList<Tab>();432int n = getTabCount();433for (int i = 0; i < n; i++) {434Component c = getComponentAt(i);435if (c instanceof Tab) {436list.add((Tab) c);437}438}439return list;440}441442private void startUpdateTimer() {443if (timer != null) {444timer.cancel();445}446TimerTask timerTask = new TimerTask() {447448public void run() {449update();450}451};452String timerName = "Timer-" + getConnectionName();453timer = new Timer(timerName, true);454timer.schedule(timerTask, 0, updateInterval);455}456457// Call on EDT458private void vmPanelDied() {459disconnect();460461if (userDisconnected) {462userDisconnected = false;463return;464}465466JOptionPane optionPane;467String msgTitle, msgExplanation, buttonStr;468469if (wasConnected) {470wasConnected = false;471msgTitle = Messages.CONNECTION_LOST1;472msgExplanation = Resources.format(Messages.CONNECTING_TO2, getConnectionName());473buttonStr = Messages.RECONNECT;474} else if (shouldUseSSL) {475msgTitle = Messages.CONNECTION_FAILED_SSL1;476msgExplanation = Resources.format(Messages.CONNECTION_FAILED_SSL2, getConnectionName());477buttonStr = Messages.INSECURE;478} else {479msgTitle = Messages.CONNECTION_FAILED1;480msgExplanation = Resources.format(Messages.CONNECTION_FAILED2, getConnectionName());481buttonStr = Messages.CONNECT;482}483484optionPane =485SheetDialog.showOptionDialog(this,486"<html><h3>" + msgTitle + "</h3>" +487"<b>" + msgExplanation + "</b>",488JOptionPane.DEFAULT_OPTION,489JOptionPane.WARNING_MESSAGE, null,490new String[]{buttonStr, Messages.CANCEL},4910);492493optionPane.addPropertyChangeListener(new PropertyChangeListener() {494495public void propertyChange(PropertyChangeEvent event) {496if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {497Object value = event.getNewValue();498499if (value == Messages.RECONNECT || value == Messages.CONNECT) {500connect();501} else if (value == Messages.INSECURE) {502shouldUseSSL = false;503connect();504} else if (!everConnected) {505try {506getFrame().setClosed(true);507} catch (PropertyVetoException ex) {508// Should not happen, but can be ignored.509}510}511}512}513});514}515516// Note: This method is called on a TimerTask thread. Any GUI manipulation517// must be performed with invokeLater() or invokeAndWait().518private Object lockObject = new Object();519520private void update() {521synchronized (lockObject) {522if (!isConnected()) {523if (wasConnected) {524EventQueue.invokeLater(new Runnable() {525526public void run() {527vmPanelDied();528}529});530}531wasConnected = false;532return;533} else {534wasConnected = true;535everConnected = true;536}537proxyClient.flush();538List<Tab> tabs = getTabs();539final int n = tabs.size();540for (int i = 0; i < n; i++) {541final int index = i;542try {543if (!proxyClient.isDead()) {544// Update tab545//546tabs.get(index).update();547// Enable tab on initial update548//549if (initialUpdate) {550EventQueue.invokeLater(new Runnable() {551552public void run() {553setEnabledAt(index, true);554}555});556}557}558} catch (Exception e) {559// Disable tab on initial update560//561if (initialUpdate) {562EventQueue.invokeLater(new Runnable() {563public void run() {564setEnabledAt(index, false);565}566});567}568}569}570571// plugin GUI update572for (ExceptionSafePlugin p : plugins.keySet()) {573SwingWorker<?, ?> sw = p.newSwingWorker();574SwingWorker<?, ?> prevSW = plugins.get(p);575// schedule SwingWorker to run only if the previous576// SwingWorker has finished its task and it hasn't started.577if (prevSW == null || prevSW.isDone()) {578if (sw == null || sw.getState() == SwingWorker.StateValue.PENDING) {579plugins.put(p, sw);580if (sw != null) {581p.executeSwingWorker(sw);582}583}584}585}586587// Set the first enabled tab in the tab's list588// as the selected tab on initial update589//590if (initialUpdate) {591EventQueue.invokeLater(new Runnable() {592public void run() {593// Select first enabled tab if current tab isn't.594int index = getSelectedIndex();595if (index < 0 || !isEnabledAt(index)) {596for (int i = 0; i < n; i++) {597if (isEnabledAt(i)) {598setSelectedIndex(i);599break;600}601}602}603}604});605initialUpdate = false;606}607}608}609610public String getHostName() {611return hostName;612}613614public int getPort() {615return port;616}617618public String getUserName() {619return userName;620}621622public String getUrl() {623return url;624}625626public String getPassword() {627return password;628}629630public String getConnectionName() {631return proxyClient.connectionName();632}633634public String getDisplayName() {635return proxyClient.getDisplayName();636}637638static class TabInfo {639640Class<? extends Tab> tabClass;641String name;642boolean tabVisible;643644TabInfo(Class<? extends Tab> tabClass, String name, boolean tabVisible) {645this.tabClass = tabClass;646this.name = name;647this.tabVisible = tabVisible;648}649}650651private void createPluginTabs() {652// add plugin tabs if not done653if (!pluginTabsAdded) {654for (JConsolePlugin p : plugins.keySet()) {655Map<String, JPanel> tabs = p.getTabs();656for (Map.Entry<String, JPanel> e : tabs.entrySet()) {657addTab(e.getKey(), e.getValue());658}659}660pluginTabsAdded = true;661}662}663664private void fireConnectedChange(boolean connected) {665for (Tab tab : getTabs()) {666tab.firePropertyChange(JConsoleContext.CONNECTION_STATE_PROPERTY, !connected, connected);667}668}669}670671672