org.fluentd.jvmwatcher.proxy.JvmClientProxy.java Source code

Java tutorial

Introduction

Here is the source code for org.fluentd.jvmwatcher.proxy.JvmClientProxy.java

Source

//
// A Java VM status Watcher for Fluent
//
// Copyright (C) 2013 Masayuki Miyake
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
package org.fluentd.jvmwatcher.proxy;

import static java.lang.management.ManagementFactory.CLASS_LOADING_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.COMPILATION_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE;
import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.MEMORY_POOL_MXBEAN_DOMAIN_TYPE;
import static java.lang.management.ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.RUNTIME_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;

import java.io.IOException;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fluentd.jvmwatcher.LocalJvmInfo;

import com.sun.management.HotSpotDiagnosticMXBean;

/**
 * This class manages the MXBens to obtain the status of the JVM. And I also do connection management of the JVM.<BR>
 * JvmClientProxy will correspond to only the local JVM.
 * @author miyake
 *
 */
public class JvmClientProxy {
    private static Log log = LogFactory.getLog(JvmClientProxy.class);

    /**
     * Java VM connection status.
     */
    private boolean isConnect_ = false;
    /**
     * Target Java VM dead flag.
     */
    private boolean isDeadServer_ = true;

    private boolean hasPlatformMXBeans_ = false;
    private boolean hasHotSpotDiagnosticMXBean_ = false;
    private boolean hasCompilationMXBean_ = false;
    private boolean supportsLockUsage_ = false;

    /**
     * Local Java VM information.
     */
    private LocalJvmInfo localJvmInfo_ = null;

    // JVM server connection information
    private JMXServiceURL jmxUrl_ = null;
    private JMXConnector jmxc_ = null;

    // JVM MBean Server connection
    private MBeanServerConnection server_ = null;

    // JMX Beans
    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<MemoryPoolClientProxy> memoryPoolList_ = null;
    private List<GarbageCollectorMXBean> garbageCollectorMBeanList_ = null;

    final static private String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=HotSpotDiagnostic";

    /**
     * @param localJvmInfo
     */
    public JvmClientProxy(LocalJvmInfo localJvmInfo) {
        this.localJvmInfo_ = localJvmInfo;
    }

    /**
     * @return
     */
    public boolean connect() {
        if (this.localJvmInfo_ == null) {
            return false;
        }

        // connect the JVM server
        if (this.localJvmInfo_.isManageable() != true) {
            try {
                // get JVM Agent address
                this.localJvmInfo_.startManagementAgent();
            } catch (IOException ex) {
                log.error("startManagementAgent error.", ex);
                return false;
            } catch (Exception ex) {
                log.error("startManagementAgent error.", ex);
                return false;
            }
        }

        // connect JVM MBean Server 
        try {
            if (this.jmxUrl_ == null) {
                this.jmxUrl_ = new JMXServiceURL(this.localJvmInfo_.getAddress());
                this.jmxc_ = JMXConnectorFactory.connect(jmxUrl_, null);
                this.server_ = this.jmxc_.getMBeanServerConnection();
            }
        } catch (MalformedURLException ex) {
            log.error(" connect JVM MBean Server error.", ex);
            return false;
        } catch (IOException ex) {
            log.error(" connect JVM MBean Server error.", ex);
            return false;
        } catch (Exception ex) {
            log.error(" connect JVM MBean Server error.", ex);
            return false;
        }

        // this client have successfully connected to the JVM server.
        this.isDeadServer_ = false;

        try {
            ObjectName objName = new ObjectName(THREAD_MXBEAN_NAME);
            this.hasPlatformMXBeans_ = this.server_.isRegistered(objName);
            this.hasHotSpotDiagnosticMXBean_ = this.server_
                    .isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME));
            // check if it has 6.0 new APIs
            if (this.hasPlatformMXBeans_ = true) {
                MBeanOperationInfo[] mopis = this.server_.getMBeanInfo(objName).getOperations();
                // look for findDeadlockedThreads operations;
                for (MBeanOperationInfo op : mopis) {
                    if (op.getName().equals("findDeadlockedThreads")) {
                        this.supportsLockUsage_ = true;
                        break;
                    }
                }

                objName = new ObjectName(COMPILATION_MXBEAN_NAME);
                this.hasCompilationMXBean_ = this.server_.isRegistered(objName);
            }

            if (this.hasPlatformMXBeans_ == true) {
                // WORKAROUND for bug 5056632
                // Check if the access role is correct by getting a RuntimeMXBean
                getRuntimeMXBean();
            }
        } catch (MalformedObjectNameException ex) {
            log.error("connect error.", ex);
            return false;
        } catch (IntrospectionException ex) {
            log.error("connect error.", ex);
            return false;
        } catch (InstanceNotFoundException ex) {
            log.error("connect error.", ex);
            return false;
        } catch (ReflectionException ex) {
            log.error("connect error.", ex);
            return false;
        } catch (IOException ex) {
            log.error("connect error.", ex);
            return false;
        } catch (Exception ex) {
            log.error("connect error.", ex);
            return false;
        }

        // connect success.
        this.isConnect_ = true;

        return true;
    }

    /**
     * @return
     */
    public boolean disconnect() {
        boolean ret = false;

        // disconnect the JVM server
        // Close MBeanServer connection
        if (this.jmxc_ != null) {
            try {
                this.jmxc_.close();
            } catch (IOException ex) {
                // Ignore ???
                log.warn("disconnect error.", ex);
            } finally {
                this.jmxUrl_ = null;
                this.server_ = null;
                this.jmxc_ = null;
            }
        }
        // Reset platform MBean references
        this.classLoadingMBean_ = null;
        this.compilationMBean_ = null;
        this.memoryMBean_ = null;
        this.operatingSystemMBean_ = null;
        this.runtimeMBean_ = null;
        this.threadMBean_ = null;
        this.sunOperatingSystemMXBean_ = null;
        this.garbageCollectorMBeanList_ = null;

        // Set connection state to false
        if (this.isDeadServer_ == false) {
            this.isDeadServer_ = true;
            this.isConnect_ = false;
            ret = true;
        }
        return ret;
    }

    /**
     * @return
     */
    public boolean isConnect() {

        return this.isConnect_;
    }

    /**
     * @return
     */
    boolean isLockUsageSupported() {
        return this.supportsLockUsage_;
    }

    /**
     * @return
     * @throws IOException
     */
    public String[] getDomains() throws IOException {
        return this.server_.getDomains();
    }

    /**
     * @return
     */
    public LocalJvmInfo getLocalJvmInfo() {
        return this.localJvmInfo_;
    }

    /**
     * @param domain
     * @return
     * @throws IOException
     */
    public Map<ObjectName, MBeanInfo> getMBeans(String domain) throws IOException {
        ObjectName objName = null;
        if (domain != null) {
            try {
                objName = new ObjectName(domain + ":*");
            } catch (MalformedObjectNameException e) {
                // should not reach here
                assert (false);
            }
        }
        Set<ObjectName> mbeans = this.server_.queryNames(objName, null);
        Map<ObjectName, MBeanInfo> result = new HashMap<ObjectName, MBeanInfo>(mbeans.size());
        Iterator<ObjectName> iterator = mbeans.iterator();
        while (iterator.hasNext()) {
            ObjectName elem = iterator.next();
            try {
                MBeanInfo info = this.server_.getMBeanInfo(elem);
                result.put(elem, info);
            } catch (IntrospectionException ex) {
                log.error("getMBeans error.", ex);
            } catch (InstanceNotFoundException ex) {
                log.error("getMBeans error.", ex);
            } catch (ReflectionException ex) {
                log.error("getMBeans error.", ex);
            }
        }
        return result;
    }

    /**
     * get a list of attributes of a named MBean.
     * 
     * @param name
     * @param attributes
     * @return
     * @throws IOException
     */
    public AttributeList getAttributes(ObjectName name, String[] attributes) throws IOException {
        AttributeList list = null;
        try {
            list = this.server_.getAttributes(name, attributes);
        } catch (InstanceNotFoundException ex) {
            // need to set up listener to listen for MBeanServerNotification.
            log.error("getAttributes error.", ex);
        } catch (ReflectionException ex) {
            log.error("getAttributes error.", ex);
        }

        return list;
    }

    /**
     * Set the value of a specific attribute of a named MBean.
     * 
     * @param name
     * @param attribute
     * @throws InvalidAttributeValueException
     * @throws MBeanException
     * @throws IOException
     */
    public void setAttribute(ObjectName name, Attribute attribute)
            throws InvalidAttributeValueException, MBeanException, IOException {
        try {
            this.server_.setAttribute(name, attribute);
        } catch (InstanceNotFoundException ex) {
            log.error("setAttribute error.", ex);
        } catch (AttributeNotFoundException ex) {
            log.error("setAttribute error.", ex);
            assert (false);
        } catch (ReflectionException ex) {
            log.error("setAttribute error.", ex);
        }
    }

    /**
     * @param name
     * @return
     * @throws IOException
     */
    public boolean isRegistered(ObjectName name) throws IOException {
        return this.server_.isRegistered(name);
    }

    /**
     * 
     * Invokes an operation of a named MBean.
     * 
     * @param name
     * @param operationName
     * @param params
     * @param signature
     * @return
     * @throws IOException
     * @throws MBeanException
     */
    public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
            throws IOException, MBeanException {
        Object result = null;
        try {
            result = this.server_.invoke(name, operationName, params, signature);
        } catch (InstanceNotFoundException ex) {
            System.err.println(ex.toString());
        } catch (ReflectionException ex) {
            System.err.println(ex.toString());
        }

        return result;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException {
        if (this.hasPlatformMXBeans_ && this.classLoadingMBean_ == null) {
            this.classLoadingMBean_ = newPlatformMXBeanProxy(this.server_, CLASS_LOADING_MXBEAN_NAME,
                    ClassLoadingMXBean.class);
        }

        return this.classLoadingMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized CompilationMXBean getCompilationMXBean() throws IOException {
        if (this.hasCompilationMXBean_ && this.compilationMBean_ == null) {
            this.compilationMBean_ = newPlatformMXBeanProxy(this.server_, COMPILATION_MXBEAN_NAME,
                    CompilationMXBean.class);
        }

        return this.compilationMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized MemoryMXBean getMemoryMXBean() throws IOException {
        if (this.hasCompilationMXBean_ && this.memoryMBean_ == null) {
            this.memoryMBean_ = newPlatformMXBeanProxy(this.server_, MEMORY_MXBEAN_NAME, MemoryMXBean.class);
        }
        return this.memoryMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException {
        if (this.hasPlatformMXBeans_ && this.runtimeMBean_ == null) {
            this.runtimeMBean_ = newPlatformMXBeanProxy(this.server_, RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
        }
        return this.runtimeMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized ThreadMXBean getThreadMXBean() throws IOException {
        if (this.hasPlatformMXBeans_ && this.threadMBean_ == null) {
            this.threadMBean_ = newPlatformMXBeanProxy(this.server_, THREAD_MXBEAN_NAME, ThreadMXBean.class);
        }
        return this.threadMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException {
        if (this.hasPlatformMXBeans_ && this.operatingSystemMBean_ == null) {
            this.operatingSystemMBean_ = newPlatformMXBeanProxy(this.server_, OPERATING_SYSTEM_MXBEAN_NAME,
                    OperatingSystemMXBean.class);
        }
        return this.operatingSystemMBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized com.sun.management.OperatingSystemMXBean getSunOperatingSystemMXBean() throws IOException {
        try {
            ObjectName objName = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME);
            if (this.sunOperatingSystemMXBean_ == null) {
                if (this.server_.isInstanceOf(objName, "com.sun.management.OperatingSystemMXBean")) {
                    this.sunOperatingSystemMXBean_ = newPlatformMXBeanProxy(this.server_,
                            OPERATING_SYSTEM_MXBEAN_NAME, com.sun.management.OperatingSystemMXBean.class);
                }
            }
        } catch (InstanceNotFoundException ex) {
            log.error("com.sun.management.OperatingSystemMXBean get error.", ex);
            return null;
        } catch (MalformedObjectNameException ex) {
            log.error("com.sun.management.OperatingSystemMXBean get error.", ex);
            return null; // should never reach here
        }

        return this.sunOperatingSystemMXBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException {
        if (this.hasHotSpotDiagnosticMXBean_ && this.hotspotDiagnosticMXBean_ == null) {
            this.hotspotDiagnosticMXBean_ = newPlatformMXBeanProxy(this.server_, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
                    HotSpotDiagnosticMXBean.class);
        }

        return this.hotspotDiagnosticMXBean_;
    }

    /**
     * @return
     * @throws IOException
     */
    public synchronized Collection<GarbageCollectorMXBean> getGarbageCollectorMXBeans() throws IOException {
        if (this.garbageCollectorMBeanList_ == null) {
            ObjectName gcName = null;

            try {
                gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");
            } catch (MalformedObjectNameException ex) {
                log.error("GarbageCollectorMXBean get error.", ex);
                return null;
            }

            Set<ObjectName> objNameSet = this.server_.queryNames(gcName, null);

            if (objNameSet != null) {
                Iterator<ObjectName> iterator = objNameSet.iterator();
                this.garbageCollectorMBeanList_ = new ArrayList<GarbageCollectorMXBean>();

                while (iterator.hasNext()) {
                    ObjectName objName = iterator.next();
                    String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",name=" + objName.getKeyProperty("name");

                    GarbageCollectorMXBean mBean = newPlatformMXBeanProxy(this.server_, name,
                            GarbageCollectorMXBean.class);
                    this.garbageCollectorMBeanList_.add(mBean);
                }
            }
        }

        return this.garbageCollectorMBeanList_;
    }

    /**
     * @return
     * @throws IOException
     */
    public long[] findDeadlockedThreads() throws IOException {
        ThreadMXBean threadMx = getThreadMXBean();
        if (this.supportsLockUsage_ && threadMx.isSynchronizerUsageSupported()) {
            return threadMx.findDeadlockedThreads();
        } else {
            return threadMx.findMonitorDeadlockedThreads();
        }
    }

    public Collection<MemoryPoolClientProxy> getMemoryPoolClientProxies() throws IOException {

        if (this.memoryPoolList_ == null) {
            ObjectName poolName = null;
            try {
                poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",*");
            } catch (MalformedObjectNameException ex) {
                log.error("MemoryPoolClientProxy get error.", ex);
                return null;
            }

            Set<ObjectName> objNameSet = this.server_.queryNames(poolName, null);

            if (objNameSet != null) {
                Iterator<ObjectName> iterator = objNameSet.iterator();

                this.memoryPoolList_ = new ArrayList<MemoryPoolClientProxy>();
                while (iterator.hasNext()) {
                    ObjectName objName = iterator.next();
                    MemoryPoolClientProxy memoryPool = new MemoryPoolClientProxy(this);

                    if (memoryPool.init(objName) == true) {
                        this.memoryPoolList_.add(memoryPool);
                    }
                }
            }
        }

        return this.memoryPoolList_;
    }

    /**
     * @param objName
     * @param interfaceClass
     * @return
     * @throws IOException
     */
    public <T> T getMXBean(ObjectName objName, Class<T> interfaceClass) throws IOException {
        return newPlatformMXBeanProxy(this.server_, objName.toString(), interfaceClass);
    }

}