Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/jconsole/VMPanel.java
38918 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 != null && (e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0 && connectedIconBounds.contains(e.getPoint())) {127128if (isConnected()) {129userDisconnected = true;130disconnect();131wasConnected = false;132} else {133connect();134}135repaint();136}137}138});139140}141private static Icon connectedIcon16 =142new ImageIcon(VMPanel.class.getResource("resources/connected16.png"));143private static Icon connectedIcon24 =144new ImageIcon(VMPanel.class.getResource("resources/connected24.png"));145private static Icon disconnectedIcon16 =146new ImageIcon(VMPanel.class.getResource("resources/disconnected16.png"));147private static Icon disconnectedIcon24 =148new ImageIcon(VMPanel.class.getResource("resources/disconnected24.png"));149private Rectangle connectedIconBounds;150151// Override to increase right inset for tab area,152// in order to reserve space for the connect toggle.153public void setUI(TabbedPaneUI ui) {154Insets insets = (Insets) UIManager.getLookAndFeelDefaults().get("TabbedPane.tabAreaInsets");155if (insets != null) {156insets = (Insets) insets.clone();157insets.right += connectedIcon24.getIconWidth() + 8;158UIManager.put("TabbedPane.tabAreaInsets", insets);159}160super.setUI(ui);161}162163// Override to paint the connect toggle164protected void paintComponent(Graphics g) {165super.paintComponent(g);166167Icon icon;168Component c0 = getComponent(0);169if (c0 != null && c0.getY() > 24) {170icon = isConnected() ? connectedIcon24 : disconnectedIcon24;171} else {172icon = isConnected() ? connectedIcon16 : disconnectedIcon16;173}174Insets insets = getInsets();175int x = getWidth() - insets.right - icon.getIconWidth() - 4;176int y = insets.top;177if (c0 != null) {178y = (c0.getY() - icon.getIconHeight()) / 2;179}180icon.paintIcon(this, g, x, y);181connectedIconBounds = new Rectangle(x, y, icon.getIconWidth(), icon.getIconHeight());182}183184public String getToolTipText(MouseEvent event) {185if (connectedIconBounds.contains(event.getPoint())) {186if (isConnected()) {187return Messages.CONNECTED_PUNCTUATION_CLICK_TO_DISCONNECT_;188} else {189return Messages.DISCONNECTED_PUNCTUATION_CLICK_TO_CONNECT_;190}191} else {192return super.getToolTipText(event);193}194}195196private synchronized void addTab(TabInfo tabInfo) {197Tab tab = instantiate(tabInfo);198if (tab != null) {199addTab(tabInfo.name, tab);200} else {201tabInfo.tabVisible = false;202}203}204205private synchronized void insertTab(TabInfo tabInfo, int index) {206Tab tab = instantiate(tabInfo);207if (tab != null) {208insertTab(tabInfo.name, null, tab, null, index);209} else {210tabInfo.tabVisible = false;211}212}213214public synchronized void removeTabAt(int index) {215super.removeTabAt(index);216}217218private Tab instantiate(TabInfo tabInfo) {219try {220Constructor<?> con = tabInfo.tabClass.getConstructor(VMPanel.class);221return (Tab) con.newInstance(this);222} catch (Exception ex) {223System.err.println(ex);224return null;225}226}227228boolean isConnected() {229return proxyClient.isConnected();230}231232public int getUpdateInterval() {233return updateInterval;234}235236/**237* WARNING NEVER CALL THIS METHOD TO MAKE JMX REQUEST238* IF assertThread == false.239* DISPATCHER THREAD IS NOT ASSERTED.240* IT IS USED TO MAKE SOME LOCAL MANIPULATIONS.241*/242ProxyClient getProxyClient(boolean assertThread) {243if (assertThread) {244return getProxyClient();245} else {246return proxyClient;247}248}249250public ProxyClient getProxyClient() {251String threadClass = Thread.currentThread().getClass().getName();252if (threadClass.equals("java.awt.EventDispatchThread")) {253String msg = "Calling VMPanel.getProxyClient() from the Event Dispatch Thread!";254new RuntimeException(msg).printStackTrace();255System.exit(1);256}257return proxyClient;258}259260public void cleanUp() {261//proxyClient.disconnect();262for (Tab tab : getTabs()) {263tab.dispose();264}265for (JConsolePlugin p : plugins.keySet()) {266p.dispose();267}268// Cancel pending update tasks269//270if (timer != null) {271timer.cancel();272}273// Stop listening to connection state events274//275proxyClient.removePropertyChangeListener(this);276}277278// Call on EDT279public void connect() {280if (isConnected()) {281// create plugin tabs if not done282createPluginTabs();283// Notify tabs284fireConnectedChange(true);285// Enable/disable tabs on initial update286initialUpdate = true;287// Start/Restart update timer on connect/reconnect288startUpdateTimer();289} else {290new Thread("VMPanel.connect") {291292public void run() {293proxyClient.connect(shouldUseSSL);294}295}.start();296}297}298299// Call on EDT300public void disconnect() {301proxyClient.disconnect();302updateFrameTitle();303}304305// Called on EDT306public void propertyChange(PropertyChangeEvent ev) {307String prop = ev.getPropertyName();308309if (prop == CONNECTION_STATE_PROPERTY) {310ConnectionState oldState = (ConnectionState) ev.getOldValue();311ConnectionState newState = (ConnectionState) ev.getNewValue();312switch (newState) {313case CONNECTING:314onConnecting();315break;316317case CONNECTED:318if (progressBar != null) {319progressBar.setIndeterminate(false);320progressBar.setValue(100);321}322closeOptionPane();323updateFrameTitle();324// create tabs if not done325createPluginTabs();326repaint();327// Notify tabs328fireConnectedChange(true);329// Enable/disable tabs on initial update330initialUpdate = true;331// Start/Restart update timer on connect/reconnect332startUpdateTimer();333break;334335case DISCONNECTED:336if (progressBar != null) {337progressBar.setIndeterminate(false);338progressBar.setValue(0);339closeOptionPane();340}341vmPanelDied();342if (oldState == ConnectionState.CONNECTED) {343// Notify tabs344fireConnectedChange(false);345}346break;347}348}349}350351// Called on EDT352private void onConnecting() {353time0 = System.currentTimeMillis();354355SwingUtilities.getWindowAncestor(this);356357String connectionName = getConnectionName();358progressBar = new JProgressBar();359progressBar.setIndeterminate(true);360JPanel progressPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));361progressPanel.add(progressBar);362363Object[] message = {364"<html><h3>" + Resources.format(Messages.CONNECTING_TO1, connectionName) + "</h3></html>",365progressPanel,366"<html><b>" + Resources.format(Messages.CONNECTING_TO2, connectionName) + "</b></html>"367};368369optionPane =370SheetDialog.showOptionDialog(this,371message,372JOptionPane.DEFAULT_OPTION,373JOptionPane.INFORMATION_MESSAGE, null,374new String[]{Messages.CANCEL},3750);376377378}379380// Called on EDT381private void closeOptionPane() {382if (optionPane != null) {383new Thread("VMPanel.sleeper") {384public void run() {385long elapsed = System.currentTimeMillis() - time0;386if (elapsed < 2000) {387try {388sleep(2000 - elapsed);389} catch (InterruptedException ex) {390// Ignore391}392}393SwingUtilities.invokeLater(new Runnable() {394395public void run() {396optionPane.setVisible(false);397progressBar = null;398}399});400}401}.start();402}403}404405void updateFrameTitle() {406VMInternalFrame vmIF = getFrame();407if (vmIF != null) {408String displayName = getDisplayName();409if (!proxyClient.isConnected()) {410displayName = Resources.format(Messages.CONNECTION_NAME__DISCONNECTED_, displayName);411}412vmIF.setTitle(displayName);413}414}415416private VMInternalFrame getFrame() {417if (vmIF == null) {418vmIF = (VMInternalFrame) SwingUtilities.getAncestorOfClass(VMInternalFrame.class,419this);420}421return vmIF;422}423424// TODO: this method is not needed when all JConsole tabs425// are migrated to use the new JConsolePlugin API.426//427// A thread safe clone of all JConsole tabs428synchronized List<Tab> getTabs() {429ArrayList<Tab> list = new ArrayList<Tab>();430int n = getTabCount();431for (int i = 0; i < n; i++) {432Component c = getComponentAt(i);433if (c instanceof Tab) {434list.add((Tab) c);435}436}437return list;438}439440private void startUpdateTimer() {441if (timer != null) {442timer.cancel();443}444TimerTask timerTask = new TimerTask() {445446public void run() {447update();448}449};450String timerName = "Timer-" + getConnectionName();451timer = new Timer(timerName, true);452timer.schedule(timerTask, 0, updateInterval);453}454455// Call on EDT456private void vmPanelDied() {457disconnect();458459if (userDisconnected) {460userDisconnected = false;461return;462}463464JOptionPane optionPane;465String msgTitle, msgExplanation, buttonStr;466467if (wasConnected) {468wasConnected = false;469msgTitle = Messages.CONNECTION_LOST1;470msgExplanation = Resources.format(Messages.CONNECTING_TO2, getConnectionName());471buttonStr = Messages.RECONNECT;472} else if (shouldUseSSL) {473msgTitle = Messages.CONNECTION_FAILED_SSL1;474msgExplanation = Resources.format(Messages.CONNECTION_FAILED_SSL2, getConnectionName());475buttonStr = Messages.INSECURE;476} else {477msgTitle = Messages.CONNECTION_FAILED1;478msgExplanation = Resources.format(Messages.CONNECTION_FAILED2, getConnectionName());479buttonStr = Messages.CONNECT;480}481482optionPane =483SheetDialog.showOptionDialog(this,484"<html><h3>" + msgTitle + "</h3>" +485"<b>" + msgExplanation + "</b>",486JOptionPane.DEFAULT_OPTION,487JOptionPane.WARNING_MESSAGE, null,488new String[]{buttonStr, Messages.CANCEL},4890);490491optionPane.addPropertyChangeListener(new PropertyChangeListener() {492493public void propertyChange(PropertyChangeEvent event) {494if (event.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) {495Object value = event.getNewValue();496497if (value == Messages.RECONNECT || value == Messages.CONNECT) {498connect();499} else if (value == Messages.INSECURE) {500shouldUseSSL = false;501connect();502} else if (!everConnected) {503try {504getFrame().setClosed(true);505} catch (PropertyVetoException ex) {506// Should not happen, but can be ignored.507}508}509}510}511});512}513514// Note: This method is called on a TimerTask thread. Any GUI manipulation515// must be performed with invokeLater() or invokeAndWait().516private Object lockObject = new Object();517518private void update() {519synchronized (lockObject) {520if (!isConnected()) {521if (wasConnected) {522EventQueue.invokeLater(new Runnable() {523524public void run() {525vmPanelDied();526}527});528}529wasConnected = false;530return;531} else {532wasConnected = true;533everConnected = true;534}535proxyClient.flush();536List<Tab> tabs = getTabs();537final int n = tabs.size();538for (int i = 0; i < n; i++) {539final int index = i;540try {541if (!proxyClient.isDead()) {542// Update tab543//544tabs.get(index).update();545// Enable tab on initial update546//547if (initialUpdate) {548EventQueue.invokeLater(new Runnable() {549550public void run() {551setEnabledAt(index, true);552}553});554}555}556} catch (Exception e) {557// Disable tab on initial update558//559if (initialUpdate) {560EventQueue.invokeLater(new Runnable() {561public void run() {562setEnabledAt(index, false);563}564});565}566}567}568569// plugin GUI update570for (ExceptionSafePlugin p : plugins.keySet()) {571SwingWorker<?, ?> sw = p.newSwingWorker();572SwingWorker<?, ?> prevSW = plugins.get(p);573// schedule SwingWorker to run only if the previous574// SwingWorker has finished its task and it hasn't started.575if (prevSW == null || prevSW.isDone()) {576if (sw == null || sw.getState() == SwingWorker.StateValue.PENDING) {577plugins.put(p, sw);578if (sw != null) {579p.executeSwingWorker(sw);580}581}582}583}584585// Set the first enabled tab in the tab's list586// as the selected tab on initial update587//588if (initialUpdate) {589EventQueue.invokeLater(new Runnable() {590public void run() {591// Select first enabled tab if current tab isn't.592int index = getSelectedIndex();593if (index < 0 || !isEnabledAt(index)) {594for (int i = 0; i < n; i++) {595if (isEnabledAt(i)) {596setSelectedIndex(i);597break;598}599}600}601}602});603initialUpdate = false;604}605}606}607608public String getHostName() {609return hostName;610}611612public int getPort() {613return port;614}615616public String getUserName() {617return userName;618}619620public String getUrl() {621return url;622}623624public String getPassword() {625return password;626}627628public String getConnectionName() {629return proxyClient.connectionName();630}631632public String getDisplayName() {633return proxyClient.getDisplayName();634}635636static class TabInfo {637638Class<? extends Tab> tabClass;639String name;640boolean tabVisible;641642TabInfo(Class<? extends Tab> tabClass, String name, boolean tabVisible) {643this.tabClass = tabClass;644this.name = name;645this.tabVisible = tabVisible;646}647}648649private void createPluginTabs() {650// add plugin tabs if not done651if (!pluginTabsAdded) {652for (JConsolePlugin p : plugins.keySet()) {653Map<String, JPanel> tabs = p.getTabs();654for (Map.Entry<String, JPanel> e : tabs.entrySet()) {655addTab(e.getKey(), e.getValue());656}657}658pluginTabsAdded = true;659}660}661662private void fireConnectedChange(boolean connected) {663for (Tab tab : getTabs()) {664tab.firePropertyChange(JConsoleContext.CONNECTION_STATE_PROPERTY, !connected, connected);665}666}667}668669670