1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 package it.tidalwave.actor.impl;
27
28 import java.lang.management.ManagementFactory;
29 import java.lang.reflect.Modifier;
30 import javax.annotation.Nonnegative;
31 import jakarta.annotation.Nonnull;
32 import java.util.HashMap;
33 import java.util.Map;
34 import it.tidalwave.actor.spi.ActorActivatorStats;
35 import javax.management.InstanceAlreadyExistsException;
36 import javax.management.InstanceNotFoundException;
37 import javax.management.MBeanRegistrationException;
38 import javax.management.MalformedObjectNameException;
39 import javax.management.NotCompliantMBeanException;
40 import javax.management.ObjectName;
41 import lombok.Getter;
42 import lombok.extern.slf4j.Slf4j;
43 import static it.tidalwave.messagebus.spi.ReflectionUtils.*;
44
45
46
47
48
49
50 @Slf4j
51 public class MBeansManager
52 {
53 @Nonnull
54 private final Object actorObject;
55
56 @Nonnull @Getter
57 private final ActorActivatorStats stats;
58
59 private ObjectName statsName;
60
61 private final Map<ObjectName, Object> mbeansMapByName = new HashMap<>();
62
63
64
65
66 public MBeansManager (@Nonnull final Object actorObject, @Nonnegative final int poolSize)
67 {
68 this.actorObject = actorObject;
69 stats = new ActorActivatorStats(poolSize);
70 }
71
72
73
74
75 public void register()
76 {
77 forEachMethodInTopDownHierarchy(actorObject, new MethodProcessorSupport()
78 {
79 @Override @Nonnull
80 public FilterResult filter (@Nonnull final Class<?> clazz)
81 {
82 mbeansMapByName.putAll(getMBeans(actorObject, clazz));
83 return FilterResult.IGNORE;
84 }
85 });
86
87 final var mBeanServer = ManagementFactory.getPlatformMBeanServer();
88
89 try
90 {
91 final var name = String.format("%s:type=%s", actorObject.getClass().getPackage().getName(),
92 actorObject.getClass().getSimpleName());
93 statsName = new ObjectName(name);
94 mBeanServer.registerMBean(stats, statsName);
95 }
96 catch (InstanceAlreadyExistsException | MalformedObjectNameException | NotCompliantMBeanException | MBeanRegistrationException e)
97 {
98 log.error("Cannot register master MBean for actor " + actorObject, e);
99 }
100
101 for (final var entry : mbeansMapByName.entrySet())
102 {
103 try
104 {
105 log.info(">>>> registering MBean {}", entry);
106 mBeanServer.registerMBean(entry.getValue(), entry.getKey());
107 }
108 catch (InstanceAlreadyExistsException | NotCompliantMBeanException | MBeanRegistrationException e)
109 {
110 log.error("Cannot register MBean: " + entry, e);
111 }
112 }
113 }
114
115
116
117
118 public void unregister()
119 {
120 final var mBeanServer = ManagementFactory.getPlatformMBeanServer();
121
122 try
123 {
124 mBeanServer.unregisterMBean(statsName);
125 }
126 catch (InstanceNotFoundException | MBeanRegistrationException e)
127 {
128 log.error("Cannot register master MBean for actor " + actorObject, e);
129 }
130
131 for (final var entry : mbeansMapByName.entrySet())
132 {
133 try
134 {
135 log.info(">>>> unregistering MBean {}", entry);
136 mBeanServer.unregisterMBean(entry.getKey());
137 }
138 catch (InstanceNotFoundException | MBeanRegistrationException e)
139 {
140 log.error("Cannot unregister MBean: " + entry, e);
141 }
142 }
143 }
144
145
146
147
148 @Nonnull
149 private static Map<ObjectName, Object> getMBeans (@Nonnull final Object actorObject, @Nonnull final Class<?> clazz)
150 {
151 final Map<ObjectName, Object> result = new HashMap<>();
152
153 for (final var field : clazz.getDeclaredFields())
154 {
155 if (!field.isSynthetic() && ((field.getModifiers() & Modifier.STATIC) == 0))
156 {
157 try
158 {
159 field.setAccessible(true);
160 final var value = field.get(actorObject);
161
162 if (value != null)
163 {
164 final var interfaces = value.getClass().getInterfaces();
165
166
167
168 if ((interfaces.length > 0) && interfaces[0].getName().endsWith("MBean"))
169 {
170 final var name = String.format("%s:type=%s", clazz.getPackage().getName(),
171 value.getClass().getSimpleName());
172 result.put(new ObjectName(name), value);
173 }
174 }
175 }
176 catch (IllegalArgumentException | MalformedObjectNameException | IllegalAccessException e)
177 {
178 log.error("Cannot handle object: {}", field);
179 }
180 }
181 }
182
183 return result;
184 }
185 }