001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.monitoring.reporting.web.plugin.thread; 018 019 import org.apache.commons.codec.binary.Base64; 020 import org.apache.commons.lang3.StringEscapeUtils; 021 import org.apache.commons.monitoring.reporting.web.handler.api.Regex; 022 import org.apache.commons.monitoring.reporting.web.handler.api.Template; 023 import org.apache.commons.monitoring.reporting.web.template.MapBuilder; 024 025 import java.util.Map; 026 import java.util.TreeMap; 027 028 public class ThreadEndpoints { 029 @Regex 030 public Template home() { 031 return new Template("threads/threads.vm", new MapBuilder<String, Object>() 032 .set("threads", listThreads()) 033 .build()); 034 } 035 036 @Regex("/([^/]*)") 037 public Template dump(final String name) { 038 final Thread thread = findThread(new String(Base64.decodeBase64(name))); 039 if (thread == null) { 040 return new Template("templates/threads/thread.vm", new MapBuilder<String, Object>().set("state", "Not found").build(), false); 041 } 042 043 return new Template( 044 "templates/threads/thread.vm", 045 new MapBuilder<String, Object>().set("state", thread.getState().name()).set("dump", StringEscapeUtils.escapeHtml4(dump(thread))).build(), 046 false); 047 } 048 049 private static Thread findThread(final String name) { 050 int count = Thread.activeCount(); 051 final Thread[] threads = new Thread[count]; 052 count = Thread.enumerate(threads); 053 054 for (int i = 0; i < count; i++) { 055 if (threads[i].getName().equals(name)) { 056 return threads[i]; 057 } 058 } 059 060 return null; 061 } 062 063 private static String dump(final Thread thread) { 064 final StackTraceElement[] stack = thread.getStackTrace(); 065 final StringBuilder builder = new StringBuilder(); 066 for (final StackTraceElement element : stack) { 067 builder.append(element.toString()).append("\n"); // toString method is fine 068 } 069 return builder.toString(); 070 } 071 072 private static Map<String, String> listThreads() { 073 final Map<String, String> out = new TreeMap<String, String>(); 074 075 int count = Thread.activeCount(); 076 final Thread[] threads = new Thread[count]; 077 count = Thread.enumerate(threads); 078 079 for (int i = 0; i < count; i++) { 080 final String name = threads[i].getName(); 081 out.put(name, Base64.encodeBase64String(name.getBytes())); 082 } 083 084 return out; 085 } 086 }