View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.controllers.threads;
12  
13  import jakarta.servlet.http.HttpServletRequest;
14  import jakarta.servlet.http.HttpServletResponse;
15  
16  import java.util.ArrayList;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.TreeMap;
20  
21  import org.apache.catalina.Context;
22  import org.springframework.beans.factory.annotation.Value;
23  import org.springframework.stereotype.Controller;
24  import org.springframework.web.bind.annotation.RequestMapping;
25  import org.springframework.web.servlet.ModelAndView;
26  
27  import psiprobe.controllers.AbstractTomcatContainerController;
28  import psiprobe.model.java.ThreadModel;
29  import psiprobe.tools.Instruments;
30  
31  /**
32   * The Class ListThreadsController.
33   */
34  @Controller
35  public class ListThreadsController extends AbstractTomcatContainerController {
36  
37    @RequestMapping(path = "/th_impl1.htm")
38    @Override
39    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
40        throws Exception {
41      return super.handleRequest(request, response);
42    }
43  
44    @Override
45    protected ModelAndView handleRequestInternal(HttpServletRequest request,
46        HttpServletResponse response) throws Exception {
47  
48      /*
49       * Create a list of webapp classloaders. This will help us to associate threads with
50       * applications.
51       */
52      List<Context> contexts = getContainerWrapper().getTomcatContainer().findContexts();
53      Map<String, String> classLoaderMap = new TreeMap<>();
54      for (Context context : contexts) {
55        if (context.getLoader() != null && context.getLoader().getClassLoader() != null) {
56          classLoaderMap.put(toUid(context.getLoader().getClassLoader()), context.getName());
57        }
58      }
59  
60      return new ModelAndView(getViewName(), "threads", enumerateThreads(classLoaderMap));
61    }
62  
63    /**
64     * Enumerate threads.
65     *
66     * @param classLoaderMap the class loader map
67     *
68     * @return the list
69     */
70    private List<ThreadModel> enumerateThreads(final Map<String, String> classLoaderMap) {
71  
72      // get top ThreadGroup
73      ThreadGroup masterGroup = Thread.currentThread().getThreadGroup();
74      while (masterGroup.getParent() != null) {
75        masterGroup = masterGroup.getParent();
76      }
77  
78      // enumerate all Threads starting from top
79      List<ThreadModel> threadList = new ArrayList<>();
80  
81      Thread[] threads = new Thread[masterGroup.activeCount()];
82      int numThreads = masterGroup.enumerate(threads);
83  
84      for (int i = 0; i < numThreads; i++) {
85        ThreadModel threadModel = new ThreadModel();
86        threadModel.setThreadClass(threads[i].getClass().getName());
87        threadModel.setName(threads[i].getName());
88        threadModel.setPriority(threads[i].getPriority());
89        threadModel.setDaemon(threads[i].isDaemon());
90        threadModel.setInterrupted(threads[i].isInterrupted());
91        if (threads[i].getThreadGroup() != null) {
92          threadModel.setGroupName(threads[i].getThreadGroup().getName());
93        }
94        Object target = Instruments.getField(threads[i], "target");
95        if (target != null) {
96          threadModel.setRunnableClassName(target.getClass().getName());
97        }
98  
99        ClassLoader cl = threads[i].getContextClassLoader();
100       if (cl != null) {
101         if (classLoaderMap != null) {
102           threadModel.setAppName(classLoaderMap.get(toUid(cl)));
103         }
104         threadModel.setClassLoader(toUid(cl));
105       }
106       threadList.add(threadModel);
107     }
108     return threadList;
109   }
110 
111   /**
112    * To uid.
113    *
114    * @param obj the obj
115    *
116    * @return the string
117    */
118   private static String toUid(Object obj) {
119     return obj.getClass().getName() + "@" + obj.hashCode();
120   }
121 
122   @Value("threads")
123   @Override
124   public void setViewName(String viewName) {
125     super.setViewName(viewName);
126   }
127 
128 }