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