com.haulmont.cuba.web.app.ui.statistics.ThreadsDatasource.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.app.ui.statistics.ThreadsDatasource.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * 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 com.haulmont.cuba.web.app.ui.statistics;

import com.haulmont.cuba.core.entity.JmxInstance;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.gui.data.impl.CollectionDatasourceImpl;
import com.haulmont.cuba.web.jmx.JmxControlAPI;
import com.haulmont.cuba.web.jmx.entity.ManagedBeanAttribute;
import com.haulmont.cuba.web.jmx.entity.ManagedBeanInfo;
import com.haulmont.cuba.web.jmx.entity.ManagedBeanOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;

import javax.management.openmbean.CompositeData;
import java.util.*;

public class ThreadsDatasource extends CollectionDatasourceImpl<ThreadSnapshot, UUID> {

    protected JmxControlAPI jmxControlAPI;

    private long prevUptime = -1;

    private Map<Long, Long> prevThread2CpuTime = new HashMap<>();

    private Map<Long, ThreadSnapshot> id2Thread = new HashMap<>();

    public ThreadsDatasource() {
        jmxControlAPI = AppBeans.get(JmxControlAPI.class);
    }

    protected Object getAttributeValue(JmxInstance node, String beanObjectName, String attrName) {
        ManagedBeanInfo bean = jmxControlAPI.getManagedBean(node, beanObjectName);
        Object res = null;
        if (bean != null) {
            ManagedBeanAttribute attr = jmxControlAPI.loadAttribute(bean, attrName);
            jmxControlAPI.loadAttributeValue(attr);
            res = attr.getValue();
        }
        return res;
    }

    @Override
    protected void loadData(Map<String, Object> params) {
        JmxInstance node = (JmxInstance) params.get("node");
        ManagedBeanInfo threadingBean = jmxControlAPI.getManagedBean(node, "java.lang:type=Threading");
        int nCPUs = (int) getAttributeValue(node, "java.lang:type=OperatingSystem", "AvailableProcessors");

        final long[] allThreadsIds = (long[]) getAttributeValue(node, "java.lang:type=Threading", "AllThreadIds");
        ManagedBeanOperation getThreadInfo = jmxControlAPI.getOperation(threadingBean, "getThreadInfo",
                new String[] { "[J" });
        CompositeData[] threadsInfo = (CompositeData[]) jmxControlAPI.invokeOperation(getThreadInfo,
                new Object[] { allThreadsIds });

        final long currentUptime = (long) getAttributeValue(node, "java.lang:type=Runtime", "Uptime");
        ManagedBeanOperation getThreadCpuTime = jmxControlAPI.getOperation(threadingBean, "getThreadCpuTime",
                new String[] { "[J" });
        long[] threadCpuTime = (long[]) jmxControlAPI.invokeOperation(getThreadCpuTime,
                new Object[] { allThreadsIds });
        if (prevUptime > 0L && currentUptime > prevUptime) {
            // elapsedTime is in ms
            long elapsedTime = currentUptime - prevUptime;
            for (int i = 0; i < allThreadsIds.length; i++) {
                // elapsedCpu is in ns
                Long threadId = allThreadsIds[i];
                Long prevCpuTimeLong = prevThread2CpuTime.get(threadId); //for new threads returns null.
                long prevCpuTime = prevCpuTimeLong != null ? prevCpuTimeLong : 0L;
                long elapsedCpu = threadCpuTime[i] - prevCpuTime;
                // cpuUsage could go higher than 100% because elapsedTime
                // and elapsedCpu are not fetched simultaneously. Limit to 99%.
                double cpuUsage = Math.min(99d, elapsedCpu / (elapsedTime * 1000000d /*convert to ns*/
                        / 100 /*percents*/ * nCPUs));
                getThreadSnapshot(threadId).setCpu(cpuUsage);
            }
        }
        prevUptime = currentUptime;
        for (int i = 0; i < allThreadsIds.length; i++) {
            long time = threadCpuTime[i] != -1L ? threadCpuTime[i] : 0L;
            prevThread2CpuTime.put(allThreadsIds[i], time);
        }

        ManagedBeanOperation findDeadlockedThreads = jmxControlAPI.getOperation(threadingBean,
                "findDeadlockedThreads", null);
        Long[] deadlockedThreads = (Long[]) jmxControlAPI.invokeOperation(findDeadlockedThreads, null);
        Set<Long> deadLockedThreadsSet = new HashSet<>();
        if (deadlockedThreads != null) {
            CollectionUtils.addAll(deadLockedThreadsSet, deadlockedThreads);
        }
        Set<Long> allThreadsSet = new HashSet<>();
        CollectionUtils.addAll(allThreadsSet, ArrayUtils.toObject(allThreadsIds));

        //remove all terminated threads.
        Collection<ThreadSnapshot> toRemove = new LinkedList<>();
        for (ThreadSnapshot snapshot : getItems()) {
            if (!allThreadsSet.contains(snapshot.getThreadId())) {
                toRemove.add(snapshot);
            }
        }
        for (ThreadSnapshot snapshot : toRemove) {
            removeItem(snapshot);
        }

        //update visual data.
        for (int i = 0; i < threadsInfo.length; i++) {
            CompositeData info = threadsInfo[i];
            if (info != null) {
                Long threadId = (Long) info.get("threadId");
                ThreadSnapshot item = getThreadSnapshot(threadId);
                item.setName((String) info.get("threadName"));
                item.setStatus(info.get("threadState").toString());
                item.setDeadLocked(deadLockedThreadsSet.contains(threadId));
            } else {
                removeItem(getThreadSnapshot(allThreadsIds[i])); //no thread info available.
            }
        }

    }

    protected ThreadSnapshot getThreadSnapshot(Long threadId) {
        ThreadSnapshot res = id2Thread.get(threadId);
        if (res == null) {
            res = new ThreadSnapshot();
            res.setThreadId(threadId);
            id2Thread.put(threadId, res);

            data.put(res.getId(), res);
            attachListener(res);
        }
        return res;
    }

    @Override
    public void clear() {
        super.clear();
        id2Thread.clear();
        prevThread2CpuTime.clear();
    }

    @Override
    public void deleted(ThreadSnapshot item) {
        super.deleted(item);
        id2Thread.remove(item.getThreadId());
        prevThread2CpuTime.remove(item.getThreadId());
    }

    protected String getStackTrace(Long threadId) {
        JmxInstance node = (JmxInstance) savedParameters.get("node");
        ManagedBeanInfo threadingBean = jmxControlAPI.getManagedBean(node, "java.lang:type=Threading");
        ManagedBeanOperation getThreadInfo = jmxControlAPI.getOperation(threadingBean, "getThreadInfo",
                new String[] { "long", "int" });
        CompositeData threadInfo = (CompositeData) jmxControlAPI.invokeOperation(getThreadInfo,
                new Object[] { threadId, Integer.MAX_VALUE });

        StringBuilder sb = new StringBuilder();
        if (threadInfo != null) {
            CompositeData[] traces = (CompositeData[]) threadInfo.get("stackTrace");
            ThreadSnapshot t = getThreadSnapshot(threadId);
            sb.append(t.getName()).append(" [id=").append(threadId).append("] (").append(t.getStatus())
                    .append(")\n");
            for (CompositeData trace : traces) {
                String className = (String) trace.get("className");
                String methodName = (String) trace.get("methodName");
                int line = (int) trace.get("lineNumber");
                sb.append(className).append(".").append(methodName).append(":").append(line).append("\n");
            }
        }
        return sb.toString();
    }
}