1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.jmx;
20
21 import java.io.IOException;
22 import java.util.Locale;
23 import java.util.Map;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.atomic.AtomicInteger;
27
28 import javax.management.InstanceNotFoundException;
29 import javax.management.MBeanRegistrationException;
30 import javax.management.MBeanServer;
31 import javax.management.ObjectName;
32
33 import org.eclipse.jetty.util.component.Container;
34 import org.eclipse.jetty.util.component.ContainerLifeCycle;
35 import org.eclipse.jetty.util.component.Dumpable;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38
39
40
41
42 public class MBeanContainer implements Container.InheritedListener, Dumpable
43 {
44 private final static Logger LOG = Log.getLogger(MBeanContainer.class.getName());
45 private final static ConcurrentMap<String, AtomicInteger> __unique = new ConcurrentHashMap<>();
46
47 public static void resetUnique()
48 {
49 __unique.clear();
50 }
51
52 private final MBeanServer _mbeanServer;
53 private final Map<Object, ObjectName> _beans = new ConcurrentHashMap<>();
54 private String _domain = null;
55
56
57
58
59
60
61
62 public ObjectName findMBean(Object object)
63 {
64 return _beans.get(object);
65 }
66
67
68
69
70
71
72
73 public Object findBean(ObjectName objectName)
74 {
75 for (Map.Entry<Object, ObjectName> entry : _beans.entrySet())
76 {
77 if (entry.getKey().equals(objectName))
78 return entry.getValue();
79 }
80 return null;
81 }
82
83
84
85
86
87
88 public MBeanContainer(MBeanServer server)
89 {
90 _mbeanServer = server;
91 }
92
93
94
95
96
97
98 public MBeanServer getMBeanServer()
99 {
100 return _mbeanServer;
101 }
102
103
104
105
106
107
108 public void setDomain(String domain)
109 {
110 _domain = domain;
111 }
112
113
114
115
116
117
118 public String getDomain()
119 {
120 return _domain;
121 }
122
123
124 @Override
125 public void beanAdded(Container parent, Object obj)
126 {
127 if (LOG.isDebugEnabled())
128 LOG.debug("beanAdded {}->{}", parent, obj);
129
130
131 ObjectName parentObjectName = null;
132 if (parent != null)
133 {
134 parentObjectName = findMBean(parent);
135 if (parentObjectName == null)
136 {
137
138 beanAdded(null, parent);
139 parentObjectName = findMBean(parent);
140 }
141 }
142
143
144 if (obj == null || _beans.containsKey(obj))
145 return;
146
147 try
148 {
149
150 Object mbean = ObjectMBean.mbeanFor(obj);
151 if (mbean == null)
152 return;
153
154 ObjectName objectName = null;
155 if (mbean instanceof ObjectMBean)
156 {
157 ((ObjectMBean)mbean).setMBeanContainer(this);
158 objectName = ((ObjectMBean)mbean).getObjectName();
159 }
160
161
162 if (objectName == null)
163 {
164
165 String domain = _domain;
166 if (domain == null)
167 domain = obj.getClass().getPackage().getName();
168
169 String type = obj.getClass().getName().toLowerCase(Locale.ENGLISH);
170 int dot = type.lastIndexOf('.');
171 if (dot >= 0)
172 type = type.substring(dot + 1);
173
174 StringBuilder buf = new StringBuilder();
175
176 String context = (mbean instanceof ObjectMBean) ? makeName(((ObjectMBean)mbean).getObjectContextBasis()) : null;
177 if (context == null && parentObjectName != null)
178 context = parentObjectName.getKeyProperty("context");
179
180 if (context != null && context.length() > 1)
181 buf.append("context=").append(context).append(",");
182
183 buf.append("type=").append(type);
184
185 String name = (mbean instanceof ObjectMBean) ? makeName(((ObjectMBean)mbean).getObjectNameBasis()) : context;
186 if (name != null && name.length() > 1)
187 buf.append(",").append("name=").append(name);
188
189 String basis = buf.toString();
190
191 AtomicInteger count = __unique.get(basis);
192 if (count == null)
193 {
194 count = new AtomicInteger();
195 AtomicInteger existing = __unique.putIfAbsent(basis, count);
196 if (existing != null)
197 count = existing;
198 }
199
200 objectName = ObjectName.getInstance(domain + ":" + basis + ",id=" + count.getAndIncrement());
201 }
202
203 _mbeanServer.registerMBean(mbean, objectName);
204 if (LOG.isDebugEnabled())
205 LOG.debug("Registered {}", objectName);
206
207 _beans.put(obj, objectName);
208 }
209 catch (Throwable x)
210 {
211 LOG.warn("bean: " + obj, x);
212 }
213 }
214
215 @Override
216 public void beanRemoved(Container parent, Object obj)
217 {
218 if (LOG.isDebugEnabled())
219 LOG.debug("beanRemoved {}", obj);
220
221 ObjectName objectName = _beans.remove(obj);
222
223 if (objectName != null)
224 unregister(objectName);
225 }
226
227
228
229
230
231 public String makeName(String basis)
232 {
233 if (basis == null)
234 return null;
235 return basis
236 .replace(':', '_')
237 .replace('*', '_')
238 .replace('?', '_')
239 .replace('=', '_')
240 .replace(',', '_')
241 .replace(' ', '_');
242 }
243
244 @Override
245 public void dump(Appendable out, String indent) throws IOException
246 {
247 ContainerLifeCycle.dumpObject(out,this);
248 ContainerLifeCycle.dump(out, indent, _beans.entrySet());
249 }
250
251 @Override
252 public String dump()
253 {
254 return ContainerLifeCycle.dump(this);
255 }
256
257 public void destroy()
258 {
259 _beans.values().stream()
260 .filter(objectName -> objectName != null)
261 .forEach(this::unregister);
262 }
263
264 private void unregister(ObjectName objectName)
265 {
266 try
267 {
268 getMBeanServer().unregisterMBean(objectName);
269 if (LOG.isDebugEnabled())
270 LOG.debug("Unregistered {}", objectName);
271 }
272 catch (MBeanRegistrationException | InstanceNotFoundException x)
273 {
274 LOG.ignore(x);
275 }
276 catch (Throwable x)
277 {
278 LOG.warn(x);
279 }
280 }
281 }