| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.tools.jconsole;  | 
 | 
 | 
 | 
import com.sun.management.HotSpotDiagnosticMXBean;  | 
 | 
import com.sun.tools.jconsole.JConsoleContext;  | 
 | 
import java.beans.PropertyChangeListener;  | 
 | 
import java.beans.PropertyChangeEvent;  | 
 | 
import java.io.IOException;  | 
 | 
import java.lang.management.*;  | 
 | 
import static java.lang.management.ManagementFactory.*;  | 
 | 
import java.lang.ref.WeakReference;  | 
 | 
import java.lang.reflect.*;  | 
 | 
import java.rmi.*;  | 
 | 
import java.rmi.registry.*;  | 
 | 
import java.rmi.server.*;  | 
 | 
import java.util.*;  | 
 | 
import javax.management.*;  | 
 | 
import javax.management.remote.*;  | 
 | 
import javax.management.remote.rmi.*;  | 
 | 
import javax.rmi.ssl.SslRMIClientSocketFactory;  | 
 | 
import javax.swing.event.SwingPropertyChangeSupport;  | 
 | 
import sun.rmi.server.UnicastRef2;  | 
 | 
import sun.rmi.transport.LiveRef;  | 
 | 
 | 
 | 
public class ProxyClient implements JConsoleContext { | 
 | 
 | 
 | 
    private ConnectionState connectionState = ConnectionState.DISCONNECTED;  | 
 | 
 | 
 | 
      | 
 | 
    private SwingPropertyChangeSupport propertyChangeSupport =  | 
 | 
                                new SwingPropertyChangeSupport(this, true);  | 
 | 
 | 
 | 
    private static Map<String, ProxyClient> cache =  | 
 | 
        Collections.synchronizedMap(new HashMap<String, ProxyClient>());  | 
 | 
 | 
 | 
    private volatile boolean isDead = true;  | 
 | 
    private String hostName = null;  | 
 | 
    private int port = 0;  | 
 | 
    private String userName = null;  | 
 | 
    private String password = null;  | 
 | 
    private boolean hasPlatformMXBeans = false;  | 
 | 
    private boolean hasHotSpotDiagnosticMXBean= false;  | 
 | 
    private boolean hasCompilationMXBean = false;  | 
 | 
    private boolean supportsLockUsage = false;  | 
 | 
 | 
 | 
    // REVISIT: VMPanel and other places relying using getUrl().  | 
 | 
 | 
 | 
      | 
 | 
    private LocalVirtualMachine lvm;  | 
 | 
 | 
 | 
      | 
 | 
    private String advancedUrl = null;  | 
 | 
 | 
 | 
    private JMXServiceURL jmxUrl = null;  | 
 | 
    private MBeanServerConnection mbsc = null;  | 
 | 
    private SnapshotMBeanServerConnection server = null;  | 
 | 
    private JMXConnector jmxc = null;  | 
 | 
    private RMIServer stub = null;  | 
 | 
    private static final SslRMIClientSocketFactory sslRMIClientSocketFactory =  | 
 | 
            new SslRMIClientSocketFactory();  | 
 | 
    private String registryHostName = null;  | 
 | 
    private int registryPort = 0;  | 
 | 
    private boolean vmConnector = false;  | 
 | 
    private boolean sslRegistry = false;  | 
 | 
    private boolean sslStub = false;  | 
 | 
    final private String connectionName;  | 
 | 
    final private String displayName;  | 
 | 
 | 
 | 
    private ClassLoadingMXBean    classLoadingMBean = null;  | 
 | 
    private CompilationMXBean     compilationMBean = null;  | 
 | 
    private MemoryMXBean          memoryMBean = null;  | 
 | 
    private OperatingSystemMXBean operatingSystemMBean = null;  | 
 | 
    private RuntimeMXBean         runtimeMBean = null;  | 
 | 
    private ThreadMXBean          threadMBean = null;  | 
 | 
 | 
 | 
    private com.sun.management.OperatingSystemMXBean sunOperatingSystemMXBean = null;  | 
 | 
    private HotSpotDiagnosticMXBean                  hotspotDiagnosticMXBean = null;  | 
 | 
 | 
 | 
    private List<MemoryPoolProxy>           memoryPoolProxies = null;  | 
 | 
    private List<GarbageCollectorMXBean>    garbageCollectorMBeans = null;  | 
 | 
 | 
 | 
    final static private String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =  | 
 | 
        "com.sun.management:type=HotSpotDiagnostic";  | 
 | 
 | 
 | 
    private ProxyClient(String hostName, int port,  | 
 | 
                        String userName, String password) throws IOException { | 
 | 
        this.connectionName = getConnectionName(hostName, port, userName);  | 
 | 
        this.displayName = connectionName;  | 
 | 
        if (hostName.equals("localhost") && port == 0) { | 
 | 
              | 
 | 
            this.hostName = hostName;  | 
 | 
            this.port = port;  | 
 | 
        } else { | 
 | 
            // Create an RMI connector client and connect it to  | 
 | 
              | 
 | 
            final String urlPath = "/jndi/rmi://" + hostName + ":" + port +  | 
 | 
                                   "/jmxrmi";  | 
 | 
            JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath); | 
 | 
            setParameters(url, userName, password);  | 
 | 
            vmConnector = true;  | 
 | 
            registryHostName = hostName;  | 
 | 
            registryPort = port;  | 
 | 
            checkSslConfig();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private ProxyClient(String url,  | 
 | 
                        String userName, String password) throws IOException { | 
 | 
        this.advancedUrl = url;  | 
 | 
        this.connectionName = getConnectionName(url, userName);  | 
 | 
        this.displayName = connectionName;  | 
 | 
        setParameters(new JMXServiceURL(url), userName, password);  | 
 | 
    }  | 
 | 
 | 
 | 
    private ProxyClient(LocalVirtualMachine lvm) throws IOException { | 
 | 
        this.lvm = lvm;  | 
 | 
        this.connectionName = getConnectionName(lvm);  | 
 | 
        this.displayName = "pid: " + lvm.vmid() + " " + lvm.displayName();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void setParameters(JMXServiceURL url, String userName, String password) { | 
 | 
        this.jmxUrl = url;  | 
 | 
        this.hostName = jmxUrl.getHost();  | 
 | 
        this.port = jmxUrl.getPort();  | 
 | 
        this.userName = userName;  | 
 | 
        this.password = password;  | 
 | 
    }  | 
 | 
 | 
 | 
    private static void checkStub(Remote stub,  | 
 | 
                                  Class<? extends Remote> stubClass) { | 
 | 
        // Check remote stub is from the expected class.  | 
 | 
          | 
 | 
        if (stub.getClass() != stubClass) { | 
 | 
            if (!Proxy.isProxyClass(stub.getClass())) { | 
 | 
                throw new SecurityException(  | 
 | 
                    "Expecting a " + stubClass.getName() + " stub!");  | 
 | 
            } else { | 
 | 
                InvocationHandler handler = Proxy.getInvocationHandler(stub);  | 
 | 
                if (handler.getClass() != RemoteObjectInvocationHandler.class) { | 
 | 
                    throw new SecurityException(  | 
 | 
                        "Expecting a dynamic proxy instance with a " +  | 
 | 
                        RemoteObjectInvocationHandler.class.getName() +  | 
 | 
                        " invocation handler!");  | 
 | 
                } else { | 
 | 
                    stub = (Remote) handler;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        // Check RemoteRef in stub is from the expected class  | 
 | 
        // "sun.rmi.server.UnicastRef2".  | 
 | 
          | 
 | 
        RemoteRef ref = ((RemoteObject)stub).getRef();  | 
 | 
        if (ref.getClass() != UnicastRef2.class) { | 
 | 
            throw new SecurityException(  | 
 | 
                "Expecting a " + UnicastRef2.class.getName() +  | 
 | 
                " remote reference in stub!");  | 
 | 
        }  | 
 | 
        // Check RMIClientSocketFactory in stub is from the expected class  | 
 | 
        // "javax.rmi.ssl.SslRMIClientSocketFactory".  | 
 | 
          | 
 | 
        LiveRef liveRef = ((UnicastRef2)ref).getLiveRef();  | 
 | 
        RMIClientSocketFactory csf = liveRef.getClientSocketFactory();  | 
 | 
        if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class) { | 
 | 
            throw new SecurityException(  | 
 | 
                "Expecting a " + SslRMIClientSocketFactory.class.getName() +  | 
 | 
                " RMI client socket factory in stub!");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final String rmiServerImplStubClassName =  | 
 | 
        "javax.management.remote.rmi.RMIServerImpl_Stub";  | 
 | 
    private static final Class<? extends Remote> rmiServerImplStubClass;  | 
 | 
 | 
 | 
    static { | 
 | 
        // FIXME: RMIServerImpl_Stub is generated at build time  | 
 | 
        // after jconsole is built.  We need to investigate if  | 
 | 
        // the Makefile can be fixed to build jconsole in the  | 
 | 
        // right order.  As a workaround for now, we dynamically  | 
 | 
        // load RMIServerImpl_Stub class instead of statically  | 
 | 
          | 
 | 
        Class<? extends Remote> serverStubClass = null;  | 
 | 
        try { | 
 | 
            serverStubClass = Class.forName(rmiServerImplStubClassName).asSubclass(Remote.class);  | 
 | 
        } catch (ClassNotFoundException e) { | 
 | 
              | 
 | 
            throw new InternalError(e.getMessage(), e);  | 
 | 
        }  | 
 | 
        rmiServerImplStubClass = serverStubClass;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void checkSslConfig() throws IOException { | 
 | 
        // Get the reference to the RMI Registry and lookup RMIServer stub  | 
 | 
          | 
 | 
        Registry registry;  | 
 | 
        try { | 
 | 
            registry =  | 
 | 
                LocateRegistry.getRegistry(registryHostName, registryPort,  | 
 | 
                                           sslRMIClientSocketFactory);  | 
 | 
            try { | 
 | 
                stub = (RMIServer) registry.lookup("jmxrmi"); | 
 | 
            } catch (NotBoundException nbe) { | 
 | 
                throw (IOException)  | 
 | 
                    new IOException(nbe.getMessage()).initCause(nbe);  | 
 | 
            }  | 
 | 
            sslRegistry = true;  | 
 | 
        } catch (IOException e) { | 
 | 
            registry =  | 
 | 
                LocateRegistry.getRegistry(registryHostName, registryPort);  | 
 | 
            try { | 
 | 
                stub = (RMIServer) registry.lookup("jmxrmi"); | 
 | 
            } catch (NotBoundException nbe) { | 
 | 
                throw (IOException)  | 
 | 
                    new IOException(nbe.getMessage()).initCause(nbe);  | 
 | 
            }  | 
 | 
            sslRegistry = false;  | 
 | 
        }  | 
 | 
        // Perform the checks for secure stub  | 
 | 
          | 
 | 
        try { | 
 | 
            checkStub(stub, rmiServerImplStubClass);  | 
 | 
            sslStub = true;  | 
 | 
        } catch (SecurityException e) { | 
 | 
            sslStub = false;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean isSslRmiRegistry() { | 
 | 
        // Check for VM connector  | 
 | 
          | 
 | 
        if (!isVmConnector()) { | 
 | 
            throw new UnsupportedOperationException(  | 
 | 
                "ProxyClient.isSslRmiRegistry() is only supported if this " +  | 
 | 
                "ProxyClient is a JMX connector for a JMX VM agent");  | 
 | 
        }  | 
 | 
        return sslRegistry;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean isSslRmiStub() { | 
 | 
        // Check for VM connector  | 
 | 
          | 
 | 
        if (!isVmConnector()) { | 
 | 
            throw new UnsupportedOperationException(  | 
 | 
                "ProxyClient.isSslRmiStub() is only supported if this " +  | 
 | 
                "ProxyClient is a JMX connector for a JMX VM agent");  | 
 | 
        }  | 
 | 
        return sslStub;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean isVmConnector() { | 
 | 
        return vmConnector;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void setConnectionState(ConnectionState state) { | 
 | 
        ConnectionState oldState = this.connectionState;  | 
 | 
        this.connectionState = state;  | 
 | 
        propertyChangeSupport.firePropertyChange(CONNECTION_STATE_PROPERTY,  | 
 | 
                                                 oldState, state);  | 
 | 
    }  | 
 | 
 | 
 | 
    public ConnectionState getConnectionState() { | 
 | 
        return this.connectionState;  | 
 | 
    }  | 
 | 
 | 
 | 
    void flush() { | 
 | 
        if (server != null) { | 
 | 
            server.flush();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    void connect(boolean requireSSL) { | 
 | 
        setConnectionState(ConnectionState.CONNECTING);  | 
 | 
        try { | 
 | 
            tryConnect(requireSSL);  | 
 | 
            setConnectionState(ConnectionState.CONNECTED);  | 
 | 
        } catch (Exception e) { | 
 | 
            if (JConsole.isDebug()) { | 
 | 
                e.printStackTrace();  | 
 | 
            }  | 
 | 
            setConnectionState(ConnectionState.DISCONNECTED);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private void tryConnect(boolean requireRemoteSSL) throws IOException { | 
 | 
        if (jmxUrl == null && "localhost".equals(hostName) && port == 0) { | 
 | 
              | 
 | 
            this.jmxc = null;  | 
 | 
            this.mbsc = ManagementFactory.getPlatformMBeanServer();  | 
 | 
            this.server = Snapshot.newSnapshot(mbsc);  | 
 | 
        } else { | 
 | 
              | 
 | 
            if (lvm != null) { | 
 | 
                if (!lvm.isManageable()) { | 
 | 
                    lvm.startManagementAgent();  | 
 | 
                    if (!lvm.isManageable()) { | 
 | 
                          | 
 | 
                        throw new IOException(lvm + "not manageable");  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                if (this.jmxUrl == null) { | 
 | 
                    this.jmxUrl = new JMXServiceURL(lvm.connectorAddress());  | 
 | 
                }  | 
 | 
            }  | 
 | 
            Map<String, Object> env = new HashMap<String, Object>();  | 
 | 
            if (requireRemoteSSL) { | 
 | 
                env.put("jmx.remote.x.check.stub", "true"); | 
 | 
            }  | 
 | 
              | 
 | 
            if (userName == null && password == null) { | 
 | 
                if (isVmConnector()) { | 
 | 
                      | 
 | 
                    if (stub == null) { | 
 | 
                        checkSslConfig();  | 
 | 
                    }  | 
 | 
                    this.jmxc = new RMIConnector(stub, null);  | 
 | 
                    jmxc.connect(env);  | 
 | 
                } else { | 
 | 
                    this.jmxc = JMXConnectorFactory.connect(jmxUrl, env);  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                env.put(JMXConnector.CREDENTIALS,  | 
 | 
                        new String[] {userName, password}); | 
 | 
                if (isVmConnector()) { | 
 | 
                      | 
 | 
                    if (stub == null) { | 
 | 
                        checkSslConfig();  | 
 | 
                    }  | 
 | 
                    this.jmxc = new RMIConnector(stub, null);  | 
 | 
                    jmxc.connect(env);  | 
 | 
                } else { | 
 | 
                    this.jmxc = JMXConnectorFactory.connect(jmxUrl, env);  | 
 | 
                }  | 
 | 
            }  | 
 | 
            this.mbsc = jmxc.getMBeanServerConnection();  | 
 | 
            this.server = Snapshot.newSnapshot(mbsc);  | 
 | 
        }  | 
 | 
        this.isDead = false;  | 
 | 
 | 
 | 
        try { | 
 | 
            ObjectName on = new ObjectName(THREAD_MXBEAN_NAME);  | 
 | 
            this.hasPlatformMXBeans = server.isRegistered(on);  | 
 | 
            this.hasHotSpotDiagnosticMXBean =  | 
 | 
                server.isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME));  | 
 | 
              | 
 | 
            if (this.hasPlatformMXBeans) { | 
 | 
                MBeanOperationInfo[] mopis = server.getMBeanInfo(on).getOperations();  | 
 | 
                  | 
 | 
                for (MBeanOperationInfo op : mopis) { | 
 | 
                    if (op.getName().equals("findDeadlockedThreads")) { | 
 | 
                        this.supportsLockUsage = true;  | 
 | 
                        break;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                on = new ObjectName(COMPILATION_MXBEAN_NAME);  | 
 | 
                this.hasCompilationMXBean = server.isRegistered(on);  | 
 | 
            }  | 
 | 
        } catch (MalformedObjectNameException e) { | 
 | 
              | 
 | 
            throw new InternalError(e.getMessage());  | 
 | 
        } catch (IntrospectionException |  | 
 | 
                 InstanceNotFoundException |  | 
 | 
                 ReflectionException e) { | 
 | 
            throw new InternalError(e.getMessage(), e);  | 
 | 
        }  | 
 | 
 | 
 | 
        if (hasPlatformMXBeans) { | 
 | 
            // WORKAROUND for bug 5056632  | 
 | 
              | 
 | 
            getRuntimeMXBean();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static ProxyClient getProxyClient(LocalVirtualMachine lvm)  | 
 | 
        throws IOException { | 
 | 
        final String key = getCacheKey(lvm);  | 
 | 
        ProxyClient proxyClient = cache.get(key);  | 
 | 
        if (proxyClient == null) { | 
 | 
            proxyClient = new ProxyClient(lvm);  | 
 | 
            cache.put(key, proxyClient);  | 
 | 
        }  | 
 | 
        return proxyClient;  | 
 | 
    }  | 
 | 
 | 
 | 
    public static String getConnectionName(LocalVirtualMachine lvm) { | 
 | 
        return Integer.toString(lvm.vmid());  | 
 | 
    }  | 
 | 
 | 
 | 
    private static String getCacheKey(LocalVirtualMachine lvm) { | 
 | 
        return Integer.toString(lvm.vmid());  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static ProxyClient getProxyClient(String url,  | 
 | 
                                             String userName, String password)  | 
 | 
        throws IOException { | 
 | 
        final String key = getCacheKey(url, userName, password);  | 
 | 
        ProxyClient proxyClient = cache.get(key);  | 
 | 
        if (proxyClient == null) { | 
 | 
            proxyClient = new ProxyClient(url, userName, password);  | 
 | 
            cache.put(key, proxyClient);  | 
 | 
        }  | 
 | 
        return proxyClient;  | 
 | 
    }  | 
 | 
 | 
 | 
    public static String getConnectionName(String url,  | 
 | 
                                           String userName) { | 
 | 
        if (userName != null && userName.length() > 0) { | 
 | 
            return userName + "@" + url;  | 
 | 
        } else { | 
 | 
            return url;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static String getCacheKey(String url,  | 
 | 
                                      String userName, String password) { | 
 | 
        return (url == null ? "" : url) + ":" +  | 
 | 
               (userName == null ? "" : userName) + ":" +  | 
 | 
               (password == null ? "" : password);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static ProxyClient getProxyClient(String hostName, int port,  | 
 | 
                                             String userName, String password)  | 
 | 
        throws IOException { | 
 | 
        final String key = getCacheKey(hostName, port, userName, password);  | 
 | 
        ProxyClient proxyClient = cache.get(key);  | 
 | 
        if (proxyClient == null) { | 
 | 
            proxyClient = new ProxyClient(hostName, port, userName, password);  | 
 | 
            cache.put(key, proxyClient);  | 
 | 
        }  | 
 | 
        return proxyClient;  | 
 | 
    }  | 
 | 
 | 
 | 
    public static String getConnectionName(String hostName, int port,  | 
 | 
                                           String userName) { | 
 | 
        String name = hostName + ":" + port;  | 
 | 
        if (userName != null && userName.length() > 0) { | 
 | 
            return userName + "@" + name;  | 
 | 
        } else { | 
 | 
            return name;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static String getCacheKey(String hostName, int port,  | 
 | 
                                      String userName, String password) { | 
 | 
        return (hostName == null ? "" : hostName) + ":" +  | 
 | 
               port + ":" +  | 
 | 
               (userName == null ? "" : userName) + ":" +  | 
 | 
               (password == null ? "" : password);  | 
 | 
    }  | 
 | 
 | 
 | 
    public String connectionName() { | 
 | 
        return connectionName;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getDisplayName() { | 
 | 
        return displayName;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String toString() { | 
 | 
        if (!isConnected()) { | 
 | 
            return Resources.format(Messages.CONNECTION_NAME__DISCONNECTED_, displayName);  | 
 | 
        } else { | 
 | 
            return displayName;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
   public MBeanServerConnection getMBeanServerConnection() { | 
 | 
       return mbsc;  | 
 | 
   }  | 
 | 
 | 
 | 
    public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() { | 
 | 
        return server;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getUrl() { | 
 | 
        return advancedUrl;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getHostName() { | 
 | 
        return hostName;  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getPort() { | 
 | 
        return port;  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getVmid() { | 
 | 
        return (lvm != null) ? lvm.vmid() : 0;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getUserName() { | 
 | 
        return userName;  | 
 | 
    }  | 
 | 
 | 
 | 
    public String getPassword() { | 
 | 
        return password;  | 
 | 
    }  | 
 | 
 | 
 | 
    public void disconnect() { | 
 | 
          | 
 | 
        stub = null;  | 
 | 
          | 
 | 
        if (jmxc != null) { | 
 | 
            try { | 
 | 
                jmxc.close();  | 
 | 
            } catch (IOException e) { | 
 | 
                // Ignore ???  | 
 | 
            }  | 
 | 
        }  | 
 | 
          | 
 | 
        classLoadingMBean = null;  | 
 | 
        compilationMBean = null;  | 
 | 
        memoryMBean = null;  | 
 | 
        operatingSystemMBean = null;  | 
 | 
        runtimeMBean = null;  | 
 | 
        threadMBean = null;  | 
 | 
        sunOperatingSystemMXBean = null;  | 
 | 
        garbageCollectorMBeans = null;  | 
 | 
          | 
 | 
        if (!isDead) { | 
 | 
            isDead = true;  | 
 | 
            setConnectionState(ConnectionState.DISCONNECTED);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public String[] getDomains() throws IOException { | 
 | 
        return server.getDomains();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Map<ObjectName, MBeanInfo> getMBeans(String domain)  | 
 | 
        throws IOException { | 
 | 
 | 
 | 
        ObjectName name = null;  | 
 | 
        if (domain != null) { | 
 | 
            try { | 
 | 
                name = new ObjectName(domain + ":*");  | 
 | 
            } catch (MalformedObjectNameException e) { | 
 | 
                  | 
 | 
                assert(false);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        Set<ObjectName> mbeans = server.queryNames(name, null);  | 
 | 
        Map<ObjectName,MBeanInfo> result =  | 
 | 
            new HashMap<ObjectName,MBeanInfo>(mbeans.size());  | 
 | 
        Iterator<ObjectName> iterator = mbeans.iterator();  | 
 | 
        while (iterator.hasNext()) { | 
 | 
            Object object = iterator.next();  | 
 | 
            if (object instanceof ObjectName) { | 
 | 
                ObjectName o = (ObjectName)object;  | 
 | 
                try { | 
 | 
                    MBeanInfo info = server.getMBeanInfo(o);  | 
 | 
                    result.put(o, info);  | 
 | 
                } catch (IntrospectionException e) { | 
 | 
                    // TODO: should log the error  | 
 | 
                } catch (InstanceNotFoundException e) { | 
 | 
                    // TODO: should log the error  | 
 | 
                } catch (ReflectionException e) { | 
 | 
                    // TODO: should log the error  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return result;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public AttributeList getAttributes(ObjectName name, String[] attributes)  | 
 | 
        throws IOException { | 
 | 
        AttributeList list = null;  | 
 | 
        try { | 
 | 
            list = server.getAttributes(name, attributes);  | 
 | 
        } catch (InstanceNotFoundException e) { | 
 | 
            // TODO: A MBean may have been unregistered.  | 
 | 
            // need to set up listener to listen for MBeanServerNotification.  | 
 | 
        } catch (ReflectionException e) { | 
 | 
            // TODO: should log the error  | 
 | 
        }  | 
 | 
        return list;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public void setAttribute(ObjectName name, Attribute attribute)  | 
 | 
        throws InvalidAttributeValueException,  | 
 | 
               MBeanException,  | 
 | 
               IOException { | 
 | 
        try { | 
 | 
            server.setAttribute(name, attribute);  | 
 | 
        } catch (InstanceNotFoundException e) { | 
 | 
            // TODO: A MBean may have been unregistered.  | 
 | 
        } catch (AttributeNotFoundException e) { | 
 | 
            assert(false);  | 
 | 
        } catch (ReflectionException e) { | 
 | 
            // TODO: should log the error  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Object invoke(ObjectName name, String operationName,  | 
 | 
                         Object[] params, String[] signature)  | 
 | 
        throws IOException, MBeanException { | 
 | 
        Object result = null;  | 
 | 
        try { | 
 | 
            result = server.invoke(name, operationName, params, signature);  | 
 | 
        } catch (InstanceNotFoundException e) { | 
 | 
            // TODO: A MBean may have been unregistered.  | 
 | 
        } catch (ReflectionException e) { | 
 | 
            // TODO: should log the error  | 
 | 
        }  | 
 | 
        return result;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException { | 
 | 
        if (hasPlatformMXBeans && classLoadingMBean == null) { | 
 | 
            classLoadingMBean =  | 
 | 
                newPlatformMXBeanProxy(server, CLASS_LOADING_MXBEAN_NAME,  | 
 | 
                                       ClassLoadingMXBean.class);  | 
 | 
        }  | 
 | 
        return classLoadingMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized CompilationMXBean getCompilationMXBean() throws IOException { | 
 | 
        if (hasCompilationMXBean && compilationMBean == null) { | 
 | 
            compilationMBean =  | 
 | 
                newPlatformMXBeanProxy(server, COMPILATION_MXBEAN_NAME,  | 
 | 
                                       CompilationMXBean.class);  | 
 | 
        }  | 
 | 
        return compilationMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Collection<MemoryPoolProxy> getMemoryPoolProxies()  | 
 | 
        throws IOException { | 
 | 
 | 
 | 
          | 
 | 
        if (memoryPoolProxies == null) { | 
 | 
            ObjectName poolName = null;  | 
 | 
            try { | 
 | 
                poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",*");  | 
 | 
            } catch (MalformedObjectNameException e) { | 
 | 
                  | 
 | 
                assert(false);  | 
 | 
            }  | 
 | 
            Set<ObjectName> mbeans = server.queryNames(poolName, null);  | 
 | 
            if (mbeans != null) { | 
 | 
                memoryPoolProxies = new ArrayList<MemoryPoolProxy>();  | 
 | 
                Iterator<ObjectName> iterator = mbeans.iterator();  | 
 | 
                while (iterator.hasNext()) { | 
 | 
                    ObjectName objName = (ObjectName) iterator.next();  | 
 | 
                    MemoryPoolProxy p = new MemoryPoolProxy(this, objName);  | 
 | 
                    memoryPoolProxies.add(p);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return memoryPoolProxies;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized Collection<GarbageCollectorMXBean> getGarbageCollectorMXBeans()  | 
 | 
        throws IOException { | 
 | 
 | 
 | 
          | 
 | 
        if (garbageCollectorMBeans == null) { | 
 | 
            ObjectName gcName = null;  | 
 | 
            try { | 
 | 
                gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");  | 
 | 
            } catch (MalformedObjectNameException e) { | 
 | 
                  | 
 | 
                assert(false);  | 
 | 
            }  | 
 | 
            Set<ObjectName> mbeans = server.queryNames(gcName, null);  | 
 | 
            if (mbeans != null) { | 
 | 
                garbageCollectorMBeans = new ArrayList<GarbageCollectorMXBean>();  | 
 | 
                Iterator<ObjectName> iterator = mbeans.iterator();  | 
 | 
                while (iterator.hasNext()) { | 
 | 
                    ObjectName on = (ObjectName) iterator.next();  | 
 | 
                    String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE +  | 
 | 
                        ",name=" + on.getKeyProperty("name"); | 
 | 
 | 
 | 
                    GarbageCollectorMXBean mBean =  | 
 | 
                        newPlatformMXBeanProxy(server, name,  | 
 | 
                                               GarbageCollectorMXBean.class);  | 
 | 
                        garbageCollectorMBeans.add(mBean);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return garbageCollectorMBeans;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized MemoryMXBean getMemoryMXBean() throws IOException { | 
 | 
        if (hasPlatformMXBeans && memoryMBean == null) { | 
 | 
            memoryMBean =  | 
 | 
                newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME,  | 
 | 
                                       MemoryMXBean.class);  | 
 | 
        }  | 
 | 
        return memoryMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException { | 
 | 
        if (hasPlatformMXBeans && runtimeMBean == null) { | 
 | 
            runtimeMBean =  | 
 | 
                newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME,  | 
 | 
                                       RuntimeMXBean.class);  | 
 | 
        }  | 
 | 
        return runtimeMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    public synchronized ThreadMXBean getThreadMXBean() throws IOException { | 
 | 
        if (hasPlatformMXBeans && threadMBean == null) { | 
 | 
            threadMBean =  | 
 | 
                newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME,  | 
 | 
                                       ThreadMXBean.class);  | 
 | 
        }  | 
 | 
        return threadMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException { | 
 | 
        if (hasPlatformMXBeans && operatingSystemMBean == null) { | 
 | 
            operatingSystemMBean =  | 
 | 
                newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME,  | 
 | 
                                       OperatingSystemMXBean.class);  | 
 | 
        }  | 
 | 
        return operatingSystemMBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized com.sun.management.OperatingSystemMXBean  | 
 | 
        getSunOperatingSystemMXBean() throws IOException { | 
 | 
 | 
 | 
        try { | 
 | 
            ObjectName on = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME);  | 
 | 
            if (sunOperatingSystemMXBean == null) { | 
 | 
                if (server.isInstanceOf(on,  | 
 | 
                        "com.sun.management.OperatingSystemMXBean")) { | 
 | 
                    sunOperatingSystemMXBean =  | 
 | 
                        newPlatformMXBeanProxy(server,  | 
 | 
                            OPERATING_SYSTEM_MXBEAN_NAME,  | 
 | 
                            com.sun.management.OperatingSystemMXBean.class);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } catch (InstanceNotFoundException e) { | 
 | 
             return null;  | 
 | 
        } catch (MalformedObjectNameException e) { | 
 | 
             return null;   | 
 | 
        }  | 
 | 
        return sunOperatingSystemMXBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException { | 
 | 
        if (hasHotSpotDiagnosticMXBean && hotspotDiagnosticMXBean == null) { | 
 | 
            hotspotDiagnosticMXBean =  | 
 | 
                newPlatformMXBeanProxy(server, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,  | 
 | 
                                       HotSpotDiagnosticMXBean.class);  | 
 | 
        }  | 
 | 
        return hotspotDiagnosticMXBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    public <T> T getMXBean(ObjectName objName, Class<T> interfaceClass)  | 
 | 
        throws IOException { | 
 | 
        return newPlatformMXBeanProxy(server,  | 
 | 
                                      objName.toString(),  | 
 | 
                                      interfaceClass);  | 
 | 
 | 
 | 
    }  | 
 | 
 | 
 | 
    // Return thread IDs of deadlocked threads or null if any.  | 
 | 
    // It finds deadlocks involving only monitors if it's a Tiger VM.  | 
 | 
    // Otherwise, it finds deadlocks involving both monitors and  | 
 | 
      | 
 | 
    public long[] findDeadlockedThreads() throws IOException { | 
 | 
        ThreadMXBean tm = getThreadMXBean();  | 
 | 
        if (supportsLockUsage && tm.isSynchronizerUsageSupported()) { | 
 | 
            return tm.findDeadlockedThreads();  | 
 | 
        } else { | 
 | 
            return tm.findMonitorDeadlockedThreads();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public synchronized void markAsDead() { | 
 | 
        disconnect();  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean isDead() { | 
 | 
        return isDead;  | 
 | 
    }  | 
 | 
 | 
 | 
    boolean isConnected() { | 
 | 
        return !isDead();  | 
 | 
    }  | 
 | 
 | 
 | 
    boolean hasPlatformMXBeans() { | 
 | 
        return this.hasPlatformMXBeans;  | 
 | 
    }  | 
 | 
 | 
 | 
    boolean hasHotSpotDiagnosticMXBean() { | 
 | 
        return this.hasHotSpotDiagnosticMXBean;  | 
 | 
    }  | 
 | 
 | 
 | 
    boolean isLockUsageSupported() { | 
 | 
        return supportsLockUsage;  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean isRegistered(ObjectName name) throws IOException { | 
 | 
        return server.isRegistered(name);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void addPropertyChangeListener(PropertyChangeListener listener) { | 
 | 
        propertyChangeSupport.addPropertyChangeListener(listener);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void addWeakPropertyChangeListener(PropertyChangeListener listener) { | 
 | 
        if (!(listener instanceof WeakPCL)) { | 
 | 
            listener = new WeakPCL(listener);  | 
 | 
        }  | 
 | 
        propertyChangeSupport.addPropertyChangeListener(listener);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void removePropertyChangeListener(PropertyChangeListener listener) { | 
 | 
        if (!(listener instanceof WeakPCL)) { | 
 | 
              | 
 | 
            for (PropertyChangeListener pcl : propertyChangeSupport.getPropertyChangeListeners()) { | 
 | 
                if (pcl instanceof WeakPCL && ((WeakPCL)pcl).get() == listener) { | 
 | 
                    listener = pcl;  | 
 | 
                    break;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        propertyChangeSupport.removePropertyChangeListener(listener);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private class WeakPCL extends WeakReference<PropertyChangeListener>  | 
 | 
                          implements PropertyChangeListener { | 
 | 
        WeakPCL(PropertyChangeListener referent) { | 
 | 
            super(referent);  | 
 | 
        }  | 
 | 
 | 
 | 
        public void propertyChange(PropertyChangeEvent pce) { | 
 | 
            PropertyChangeListener pcl = get();  | 
 | 
 | 
 | 
            if (pcl == null) { | 
 | 
                // The referent listener was GC'ed, we're no longer  | 
 | 
                  | 
 | 
                dispose();  | 
 | 
            } else { | 
 | 
                pcl.propertyChange(pce);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        private void dispose() { | 
 | 
            removePropertyChangeListener(this);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    //  | 
 | 
    // Snapshot MBeanServerConnection:  | 
 | 
    //  | 
 | 
    // This is an object that wraps an existing MBeanServerConnection and adds  | 
 | 
    // caching to it, as follows:  | 
 | 
    //  | 
 | 
    // - The first time an attribute is called in a given MBean, the result is  | 
 | 
    //   cached. Every subsequent time getAttribute is called for that attribute  | 
 | 
    //   the cached result is returned.  | 
 | 
    //  | 
 | 
    // - Before every call to VMPanel.update() or when the Refresh button in the  | 
 | 
    //   Attributes table is pressed down the attributes cache is flushed. Then  | 
 | 
    //   any subsequent call to getAttribute will retrieve all the values for  | 
 | 
    //   the attributes that are known to the cache.  | 
 | 
    //  | 
 | 
    // - The attributes cache uses a learning approach and only the attributes  | 
 | 
    //   that are in the cache will be retrieved between two subsequent updates.  | 
 | 
    //  | 
 | 
 | 
 | 
    public interface SnapshotMBeanServerConnection  | 
 | 
            extends MBeanServerConnection { | 
 | 
          | 
 | 
 | 
 | 
         */  | 
 | 
        public void flush();  | 
 | 
    }  | 
 | 
 | 
 | 
    public static class Snapshot { | 
 | 
        private Snapshot() { | 
 | 
        }  | 
 | 
        public static SnapshotMBeanServerConnection  | 
 | 
                newSnapshot(MBeanServerConnection mbsc) { | 
 | 
            final InvocationHandler ih = new SnapshotInvocationHandler(mbsc);  | 
 | 
            return (SnapshotMBeanServerConnection) Proxy.newProxyInstance(  | 
 | 
                    Snapshot.class.getClassLoader(),  | 
 | 
                    new Class[] {SnapshotMBeanServerConnection.class}, | 
 | 
                    ih);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static class SnapshotInvocationHandler implements InvocationHandler { | 
 | 
 | 
 | 
        private final MBeanServerConnection conn;  | 
 | 
        private Map<ObjectName, NameValueMap> cachedValues = newMap();  | 
 | 
        private Map<ObjectName, Set<String>> cachedNames = newMap();  | 
 | 
 | 
 | 
        @SuppressWarnings("serial") | 
 | 
        private static final class NameValueMap  | 
 | 
                extends HashMap<String, Object> {} | 
 | 
 | 
 | 
        SnapshotInvocationHandler(MBeanServerConnection conn) { | 
 | 
            this.conn = conn;  | 
 | 
        }  | 
 | 
 | 
 | 
        synchronized void flush() { | 
 | 
            cachedValues = newMap();  | 
 | 
        }  | 
 | 
 | 
 | 
        public Object invoke(Object proxy, Method method, Object[] args)  | 
 | 
                throws Throwable { | 
 | 
            final String methodName = method.getName();  | 
 | 
            if (methodName.equals("getAttribute")) { | 
 | 
                return getAttribute((ObjectName) args[0], (String) args[1]);  | 
 | 
            } else if (methodName.equals("getAttributes")) { | 
 | 
                return getAttributes((ObjectName) args[0], (String[]) args[1]);  | 
 | 
            } else if (methodName.equals("flush")) { | 
 | 
                flush();  | 
 | 
                return null;  | 
 | 
            } else { | 
 | 
                try { | 
 | 
                    return method.invoke(conn, args);  | 
 | 
                } catch (InvocationTargetException e) { | 
 | 
                    throw e.getCause();  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        private Object getAttribute(ObjectName objName, String attrName)  | 
 | 
                throws MBeanException, InstanceNotFoundException,  | 
 | 
                AttributeNotFoundException, ReflectionException, IOException { | 
 | 
            final NameValueMap values = getCachedAttributes(  | 
 | 
                    objName, Collections.singleton(attrName));  | 
 | 
            Object value = values.get(attrName);  | 
 | 
            if (value != null || values.containsKey(attrName)) { | 
 | 
                return value;  | 
 | 
            }  | 
 | 
            // Not in cache, presumably because it was omitted from the  | 
 | 
            // getAttributes result because of an exception.  Following  | 
 | 
              | 
 | 
            return conn.getAttribute(objName, attrName);  | 
 | 
        }  | 
 | 
 | 
 | 
        private AttributeList getAttributes(  | 
 | 
                ObjectName objName, String[] attrNames) throws  | 
 | 
                InstanceNotFoundException, ReflectionException, IOException { | 
 | 
            final NameValueMap values = getCachedAttributes(  | 
 | 
                    objName,  | 
 | 
                    new TreeSet<String>(Arrays.asList(attrNames)));  | 
 | 
            final AttributeList list = new AttributeList();  | 
 | 
            for (String attrName : attrNames) { | 
 | 
                final Object value = values.get(attrName);  | 
 | 
                if (value != null || values.containsKey(attrName)) { | 
 | 
                    list.add(new Attribute(attrName, value));  | 
 | 
                }  | 
 | 
            }  | 
 | 
            return list;  | 
 | 
        }  | 
 | 
 | 
 | 
        private synchronized NameValueMap getCachedAttributes(  | 
 | 
                ObjectName objName, Set<String> attrNames) throws  | 
 | 
                InstanceNotFoundException, ReflectionException, IOException { | 
 | 
            NameValueMap values = cachedValues.get(objName);  | 
 | 
            if (values != null && values.keySet().containsAll(attrNames)) { | 
 | 
                return values;  | 
 | 
            }  | 
 | 
            attrNames = new TreeSet<String>(attrNames);  | 
 | 
            Set<String> oldNames = cachedNames.get(objName);  | 
 | 
            if (oldNames != null) { | 
 | 
                attrNames.addAll(oldNames);  | 
 | 
            }  | 
 | 
            values = new NameValueMap();  | 
 | 
            final AttributeList attrs = conn.getAttributes(  | 
 | 
                    objName,  | 
 | 
                    attrNames.toArray(new String[attrNames.size()]));  | 
 | 
            for (Attribute attr : attrs.asList()) { | 
 | 
                values.put(attr.getName(), attr.getValue());  | 
 | 
            }  | 
 | 
            cachedValues.put(objName, values);  | 
 | 
            cachedNames.put(objName, attrNames);  | 
 | 
            return values;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        private static <K, V> Map<K, V> newMap() { | 
 | 
            return new HashMap<K, V>();  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |