1
2
3
4
5
6
7
8
9
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
38
39 @Controller
40 public class ThreadStackController extends ParameterizableViewController {
41
42
43 private int stackElementCount = 20;
44
45
46
47
48
49
50 public int getStackElementCount() {
51 return stackElementCount;
52 }
53
54
55
56
57
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
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 }