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