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.lang.management.ManagementFactory;
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  import javax.management.MBeanServer;
21  import javax.management.MalformedObjectNameException;
22  import javax.management.ObjectName;
23  import javax.management.openmbean.CompositeData;
24  
25  import org.springframework.beans.factory.annotation.Value;
26  import org.springframework.stereotype.Controller;
27  import org.springframework.web.bind.ServletRequestBindingException;
28  import org.springframework.web.bind.ServletRequestUtils;
29  import org.springframework.web.bind.annotation.RequestMapping;
30  import org.springframework.web.servlet.ModelAndView;
31  import org.springframework.web.servlet.mvc.ParameterizableViewController;
32  
33  import psiprobe.model.ThreadStackElement;
34  import psiprobe.tools.JmxTools;
35  
36  /**
37   * The Class ThreadStackController.
38   */
39  @Controller
40  public class ThreadStackController extends ParameterizableViewController {
41  
42    /** The stack element count. */
43    private int stackElementCount = 20;
44  
45    /**
46     * Gets the stack element count.
47     *
48     * @return the stack element count
49     */
50    public int getStackElementCount() {
51      return stackElementCount;
52    }
53  
54    /**
55     * Sets the stack element count.
56     *
57     * @param stackElementCount the new stack element count
58     */
59    @Value("100")
60    public void setStackElementCount(int stackElementCount) {
61      this.stackElementCount = stackElementCount;
62    }
63  
64    @RequestMapping(path = "/app/threadstack.ajax")
65    @Override
66    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
67        throws Exception {
68      return super.handleRequest(request, response);
69    }
70  
71    @Override
72    protected ModelAndView handleRequestInternal(HttpServletRequest request,
73        HttpServletResponse response)
74        throws ServletRequestBindingException, MalformedObjectNameException {
75  
76      long threadId = ServletRequestUtils.getLongParameter(request, "id", -1);
77      String threadName = ServletRequestUtils.getStringParameter(request, "name");
78  
79      MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
80      ObjectName objectNameThreading = new ObjectName("java.lang:type=Threading");
81  
82      if (threadId == -1 && threadName != null) {
83        // find thread by name
84        for (long id : (long[]) JmxTools.getAttribute(mbeanServer, objectNameThreading,
85            "AllThreadIds")) {
86          CompositeData cd = (CompositeData) JmxTools.invoke(mbeanServer, objectNameThreading,
87              "getThreadInfo", new Object[] {id}, new String[] {"long"});
88          String name = JmxTools.getStringAttr(cd, "threadName");
89          if (threadName.equals(name)) {
90            threadId = id;
91            break;
92          }
93        }
94      }
95  
96      List<ThreadStackElement> stack = null;
97      if (mbeanServer.queryMBeans(objectNameThreading, null) != null && threadId != -1) {
98  
99        CompositeData cd =
100           (CompositeData) JmxTools.invoke(mbeanServer, objectNameThreading, "getThreadInfo",
101               new Object[] {threadId, stackElementCount}, new String[] {"long", "int"});
102       if (cd != null) {
103         CompositeData[] elements = (CompositeData[]) cd.get("stackTrace");
104         threadName = JmxTools.getStringAttr(cd, "threadName");
105 
106         stack = new ArrayList<>(elements.length);
107 
108         for (CompositeData cd2 : elements) {
109           ThreadStackElement tse = new ThreadStackElement();
110           tse.setClassName(JmxTools.getStringAttr(cd2, "className"));
111           tse.setFileName(JmxTools.getStringAttr(cd2, "fileName"));
112           tse.setMethodName(JmxTools.getStringAttr(cd2, "methodName"));
113           tse.setLineNumber(JmxTools.getIntAttr(cd2, "lineNumber", -1));
114           tse.setNativeMethod(JmxTools.getBooleanAttr(cd2, "nativeMethod"));
115           stack.add(tse);
116         }
117       }
118     }
119 
120     return new ModelAndView(getViewName(), "stack", stack).addObject("threadName", threadName);
121   }
122 
123   @Value("ajax/ThreadStack")
124   @Override
125   public void setViewName(String viewName) {
126     super.setViewName(viewName);
127   }
128 
129 }