001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.servlet;
020
021import java.io.Serializable;
022import java.lang.Thread.State;
023import java.lang.management.ClassLoadingMXBean;
024import java.lang.management.ManagementFactory;
025import java.lang.management.MemoryMXBean;
026import java.lang.management.MemoryUsage;
027import java.lang.management.ThreadInfo;
028import java.lang.management.ThreadMXBean;
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.Collections;
032import java.util.Comparator;
033import java.util.Date;
034import java.util.HashMap;
035import java.util.List;
036import java.util.Map;
037
038@SuppressWarnings("serial")
039public class JVMInfo implements Serializable {
040
041    private static Map<State, Integer> threadStateOrdering;
042    private final MemoryMXBean memoryMXBean;
043    private final ClassLoadingMXBean classLoadingMXBean;
044    private final ThreadMXBean threadMXBean;
045    private List<JThreadInfo> jThreadInfos;
046    private String threadSortOrder;
047    private Integer cpuMonitorTime = 0;
048    private int blockedThreads = 0;
049    private int runnableThreads = 0;
050    private int waitingThreads = 0;
051    private int timedWaitingThreads = 0;
052    private int newThreads = 0;
053    private int terminatedThreads = 0;
054
055    static {
056        threadStateOrdering = new HashMap<State, Integer>();
057        threadStateOrdering.put(State.RUNNABLE, 1);
058        threadStateOrdering.put(State.BLOCKED, 2);
059        threadStateOrdering.put(State.WAITING, 3);
060        threadStateOrdering.put(State.TIMED_WAITING, 4);
061        threadStateOrdering.put(State.NEW, 5);
062        threadStateOrdering.put(State.TERMINATED, 6);
063    }
064
065    public JVMInfo() {
066        memoryMXBean = ManagementFactory.getMemoryMXBean();
067        classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
068        threadMXBean = ManagementFactory.getThreadMXBean();
069    }
070
071    public String getThreadSortOrder() {
072        return threadSortOrder;
073    }
074
075    public void setThreadSortOrder(String threadSortOrder) {
076        this.threadSortOrder = threadSortOrder;
077    }
078
079    public String getCpuMonitorTime() {
080        return cpuMonitorTime.toString();
081    }
082
083    public void setCpuMonitorTime(String sleepTime) {
084        if (sleepTime != null) {
085            this.cpuMonitorTime = Integer.parseInt(sleepTime);
086        }
087    }
088
089    public String getHeapMemoryUsage() {
090        MemoryUsage hmu = memoryMXBean.getHeapMemoryUsage();
091        StringBuffer sb = new StringBuffer(60);
092        sb.append("INIT=").append(hmu.getInit());
093        sb.append("&nbsp;&nbsp;USED=").append(hmu.getUsed());
094        sb.append("&nbsp;&nbsp;COMMITTED=").append(hmu.getCommitted());
095        sb.append("&nbsp;&nbsp;MAX=").append(hmu.getMax());
096        return sb.toString();
097    }
098
099    public String getNonHeapMemoryUsage() {
100        MemoryUsage nhmu = memoryMXBean.getNonHeapMemoryUsage();
101        StringBuffer sb = new StringBuffer(60);
102        sb.append("INIT=").append(nhmu.getInit());
103        sb.append("&nbsp;&nbsp;USED=").append(nhmu.getUsed());
104        sb.append("&nbsp;&nbsp;COMMITTED=").append(nhmu.getCommitted());
105        sb.append("&nbsp;&nbsp;MAX=").append(nhmu.getMax());
106        return sb.toString();
107    }
108
109    public String getClassLoadingInfo() {
110        StringBuffer sb = new StringBuffer(150);
111        sb.append("Total Loaded Classes=").append(classLoadingMXBean.getTotalLoadedClassCount());
112        sb.append("&nbsp;&nbsp;Loaded Classes=").append(classLoadingMXBean.getLoadedClassCount());
113        sb.append("&nbsp;&nbsp;Unloaded Classes=").append(classLoadingMXBean.getUnloadedClassCount());
114        return sb.toString();
115    }
116
117    public String getThreadInfo() throws InterruptedException {
118        getThreads();
119        StringBuffer sb = new StringBuffer(150);
120        sb.append("Thread Count=").append(threadMXBean.getThreadCount());
121        sb.append("&nbsp;&nbsp;Peak Thread Count=").append(threadMXBean.getPeakThreadCount());
122        sb.append("&nbsp;&nbsp;Total Started Threads=").append(threadMXBean.getTotalStartedThreadCount());
123        sb.append("&nbsp;&nbsp;Deamon Threads=").append(threadMXBean.getDaemonThreadCount());
124        sb.append("<br /> &nbsp;&nbsp;&nbsp;&nbsp;RUNNABLE=").append(runnableThreads);
125        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;BLOCKED=").append(blockedThreads);
126        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;WAITING=").append(waitingThreads);
127        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;TIMED_WAITING=").append(timedWaitingThreads);
128        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;NEW=").append(newThreads);
129        sb.append("&nbsp;&nbsp;&nbsp;&nbsp;TERMINATED=").append(terminatedThreads);
130        sb.append("<br /> &nbsp;&nbsp;&nbsp;&nbsp;Time of Thread Dump=").append(new Date().toString());
131        return sb.toString();
132    }
133
134    public Collection<JThreadInfo> getThreads() throws InterruptedException {
135        if (jThreadInfos == null) {
136            jThreadInfos = getThreadInfos();
137            Collections.sort(jThreadInfos, new ThreadComparator(threadSortOrder));
138        }
139        return jThreadInfos;
140    }
141
142    private List<JThreadInfo> getThreadInfos() throws InterruptedException {
143        ThreadInfo[] threads = threadMXBean.dumpAllThreads(false, false);
144        Map<Long, JThreadInfo> oldThreadInfoMap = new HashMap<Long, JThreadInfo>();
145        for (ThreadInfo thread : threads) {
146            long cpuTime = -1L;
147            long userTime = -1L;
148            long threadId = thread.getThreadId();
149            if (threadMXBean.isThreadCpuTimeSupported() && threadMXBean.isThreadCpuTimeEnabled()) {
150                cpuTime = threadMXBean.getThreadCpuTime(threadId);
151                userTime = threadMXBean.getThreadUserTime(threadId);
152            }
153            oldThreadInfoMap.put(thread.getThreadId(), new JThreadInfo(cpuTime, userTime, thread));
154        }
155        Thread.sleep(cpuMonitorTime);
156        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
157        List<JThreadInfo> jThreadInfos = new ArrayList<JThreadInfo>(threadInfos.length);
158        for (int i = 0; i < threadInfos.length; i++) {
159            ThreadInfo threadInfo = threadInfos[i];
160            long threadId = threadInfo.getThreadId();
161            long cpuTime = -1L;
162            long userTime = -1L;
163            if (threadMXBean.isThreadCpuTimeSupported() && threadMXBean.isThreadCpuTimeEnabled()) {
164                JThreadInfo oldThread = oldThreadInfoMap.get(threadInfo.getThreadId());
165                if (oldThread == null) {
166                    cpuTime = threadMXBean.getThreadCpuTime(threadId);
167                    userTime = threadMXBean.getThreadUserTime(threadId);
168                }
169                else {
170                    cpuTime = threadMXBean.getThreadCpuTime(threadId) - oldThread.getCpuTime();
171                    userTime = threadMXBean.getThreadUserTime(threadId) - oldThread.getUserTime();
172                }
173            }
174            jThreadInfos.add(new JThreadInfo(cpuTime, userTime, threadInfo));
175            switch (threadInfo.getThreadState()) {
176                case RUNNABLE:
177                    runnableThreads++;
178                    break;
179                case BLOCKED:
180                    blockedThreads++;
181                    break;
182                case WAITING:
183                    waitingThreads++;
184                    break;
185                case TIMED_WAITING:
186                    timedWaitingThreads++;
187                    break;
188                case NEW:
189                    newThreads++;
190                    break;
191                case TERMINATED:
192                    terminatedThreads++;
193                    break;
194            }
195        }
196        return jThreadInfos;
197    }
198
199    public static final class JThreadInfo {
200        private long cpuTime;
201        private long userTime;
202        private ThreadInfo threadInfo;
203
204        public JThreadInfo(long cpuTime, long userTime, ThreadInfo threadInfo) {
205            this.cpuTime = cpuTime;
206            this.userTime = userTime;
207            this.threadInfo = threadInfo;
208        }
209
210        public long getCpuTime() {
211            return cpuTime;
212        }
213
214        public long getUserTime() {
215            return userTime;
216        }
217
218        public ThreadInfo getThreadInfo() {
219            return threadInfo;
220        }
221
222    }
223
224    private static final class ThreadComparator implements Comparator<JThreadInfo> {
225
226        private String threadSortOrder;
227
228        public ThreadComparator(String threadSortOrder) {
229            this.threadSortOrder = threadSortOrder;
230        }
231
232        @Override
233        public int compare(JThreadInfo jt1, JThreadInfo jt2) {
234            ThreadInfo o1 = jt1.getThreadInfo();
235            ThreadInfo o2 = jt2.getThreadInfo();
236            if ("cpu".equals(threadSortOrder)) {
237                int result = (int) (jt2.getCpuTime() - jt1.getCpuTime());
238                if (result == 0) {
239                    return compareId(o1, o2);
240                }
241                return result;
242            }
243            else if ("name".equals(threadSortOrder)) {
244                return compareName(o1, o2);
245            }
246            else {
247                // state
248                if (o1.getThreadState().equals(o2.getThreadState())) {
249                    return compareName(o1, o2);
250                }
251                else {
252                    return (int) threadStateOrdering.get(o1.getThreadState())
253                            - threadStateOrdering.get(o2.getThreadState());
254                }
255            }
256        }
257
258        private int compareId(ThreadInfo o1, ThreadInfo o2) {
259            Long id1 = o1.getThreadId();
260            Long id2 = o2.getThreadId();
261            return id1.compareTo(id2);
262        }
263
264        private int compareName(ThreadInfo o1, ThreadInfo o2) {
265            int result = o1.getThreadName().compareTo(o2.getThreadName());
266            if (result == 0) {
267                Long id1 = o1.getThreadId();
268                Long id2 = o2.getThreadId();
269                return id1.compareTo(id2);
270            }
271            return result;
272        }
273
274    }
275
276}