1 /* |
|
2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 package com.sun.jmx.interceptor; |
|
26 |
|
27 import com.sun.jmx.mbeanserver.Util; |
|
28 import java.io.ObjectInputStream; |
|
29 import java.util.Collections; |
|
30 import java.util.HashSet; |
|
31 import java.util.Set; |
|
32 import java.util.TreeSet; |
|
33 import java.util.logging.Level; |
|
34 import java.util.logging.Logger; |
|
35 import javax.management.Attribute; |
|
36 import javax.management.AttributeList; |
|
37 import javax.management.AttributeNotFoundException; |
|
38 import javax.management.DynamicMBean; |
|
39 import javax.management.DynamicWrapperMBean; |
|
40 import javax.management.InstanceAlreadyExistsException; |
|
41 import javax.management.InstanceNotFoundException; |
|
42 import javax.management.IntrospectionException; |
|
43 import javax.management.InvalidAttributeValueException; |
|
44 import javax.management.JMRuntimeException; |
|
45 import javax.management.ListenerNotFoundException; |
|
46 import javax.management.MBeanException; |
|
47 import javax.management.MBeanInfo; |
|
48 import javax.management.MBeanRegistrationException; |
|
49 import javax.management.MBeanServer; |
|
50 import javax.management.MalformedObjectNameException; |
|
51 import javax.management.NotCompliantMBeanException; |
|
52 import javax.management.NotificationBroadcaster; |
|
53 import javax.management.NotificationEmitter; |
|
54 import javax.management.NotificationFilter; |
|
55 import javax.management.NotificationListener; |
|
56 import javax.management.ObjectInstance; |
|
57 import javax.management.ObjectName; |
|
58 import javax.management.OperationsException; |
|
59 import javax.management.QueryEval; |
|
60 import javax.management.QueryExp; |
|
61 import javax.management.ReflectionException; |
|
62 import javax.management.RuntimeOperationsException; |
|
63 import javax.management.loading.ClassLoaderRepository; |
|
64 |
|
65 /** |
|
66 * <p>Base class for custom implementations of the {@link MBeanServer} |
|
67 * interface. The commonest use of this class is as the {@linkplain |
|
68 * JMXNamespace#getSourceServer() source server} for a {@link |
|
69 * JMXNamespace}, although this class can be used anywhere an {@code |
|
70 * MBeanServer} instance is required. Note that the usual ways to |
|
71 * obtain an {@code MBeanServer} instance are either to use {@link |
|
72 * java.lang.management.ManagementFactory#getPlatformMBeanServer() |
|
73 * ManagementFactory.getPlatformMBeanServer()} or to use the {@code |
|
74 * newMBeanServer} or {@code createMBeanServer} methods from {@link |
|
75 * javax.management.MBeanServerFactory MBeanServerFactory}. {@code |
|
76 * MBeanServerSupport} is for certain cases where those are not |
|
77 * appropriate.</p> |
|
78 * |
|
79 * <p>There are two main use cases for this class: <a |
|
80 * href="#special-purpose">special-purpose MBeanServer implementations</a>, |
|
81 * and <a href="#virtual">namespaces containing Virtual MBeans</a>. The next |
|
82 * sections explain these use cases.</p> |
|
83 * |
|
84 * <p>In the simplest case, a subclass needs to implement only two methods:</p> |
|
85 * |
|
86 * <ul> |
|
87 * <li> |
|
88 * {@link #getNames getNames} which returns the name of |
|
89 * all MBeans handled by this {@code MBeanServer}. |
|
90 * </li> |
|
91 * <li> |
|
92 * {@link #getDynamicMBeanFor getDynamicMBeanFor} which returns a |
|
93 * {@link DynamicMBean} that can be used to invoke operations and |
|
94 * obtain meta data (MBeanInfo) on a given MBean. |
|
95 * </li> |
|
96 * </ul> |
|
97 * |
|
98 * <p>Subclasses can create such {@link DynamicMBean} MBeans on the fly - for |
|
99 * instance, using the class {@link javax.management.StandardMBean}, just for |
|
100 * the duration of an MBeanServer method call.</p> |
|
101 * |
|
102 * <h4 id="special-purpose">Special-purpose MBeanServer implementations</h4> |
|
103 * |
|
104 * <p>In some cases |
|
105 * the general-purpose {@code MBeanServer} that you get from |
|
106 * {@link javax.management.MBeanServerFactory MBeanServerFactory} is not |
|
107 * appropriate. You might need different security checks, or you might |
|
108 * want a mock {@code MBeanServer} suitable for use in tests, or you might |
|
109 * want a simplified and optimized {@code MBeanServer} for a special purpose.</p> |
|
110 * |
|
111 * <p>As an example of a special-purpose {@code MBeanServer}, the class {@link |
|
112 * javax.management.QueryNotificationFilter QueryNotificationFilter} constructs |
|
113 * an {@code MBeanServer} instance every time it filters a notification, |
|
114 * with just one MBean that represents the notification. Although it could |
|
115 * use {@code MBeanServerFactory.newMBeanServer}, a special-purpose {@code |
|
116 * MBeanServer} will be quicker to create, use less memory, and have simpler |
|
117 * methods that execute faster.</p> |
|
118 * |
|
119 * <p>Here is an example of a special-purpose {@code MBeanServer} |
|
120 * implementation that contains exactly one MBean, which is specified at the |
|
121 * time of creation.</p> |
|
122 * |
|
123 * <pre> |
|
124 * public class SingletonMBeanServer extends MBeanServerSupport { |
|
125 * private final ObjectName objectName; |
|
126 * private final DynamicMBean mbean; |
|
127 * |
|
128 * public SingletonMBeanServer(ObjectName objectName, DynamicMBean mbean) { |
|
129 * this.objectName = objectName; |
|
130 * this.mbean = mbean; |
|
131 * } |
|
132 * |
|
133 * @Override |
|
134 * protected {@code Set<ObjectName>} {@link #getNames getNames}() { |
|
135 * return Collections.singleton(objectName); |
|
136 * } |
|
137 * |
|
138 * @Override |
|
139 * public DynamicMBean {@link #getDynamicMBeanFor |
|
140 * getDynamicMBeanFor}(ObjectName name) |
|
141 * throws InstanceNotFoundException { |
|
142 * if (objectName.equals(name)) |
|
143 * return mbean; |
|
144 * else |
|
145 * throw new InstanceNotFoundException(name); |
|
146 * } |
|
147 * } |
|
148 * </pre> |
|
149 * |
|
150 * <p>Using this class, you could make an {@code MBeanServer} that contains |
|
151 * a {@link javax.management.timer.Timer Timer} MBean like this:</p> |
|
152 * |
|
153 * <pre> |
|
154 * Timer timer = new Timer(); |
|
155 * DynamicMBean mbean = new {@link javax.management.StandardMBean |
|
156 * StandardMBean}(timer, TimerMBean.class); |
|
157 * ObjectName name = new ObjectName("com.example:type=Timer"); |
|
158 * MBeanServer timerMBS = new SingletonMBeanServer(name, mbean); |
|
159 * </pre> |
|
160 * |
|
161 * <p>When {@code getDynamicMBeanFor} always returns the same object for the |
|
162 * same name, as here, notifications work in the expected way: if the object |
|
163 * is a {@link NotificationEmitter} then listeners can be added using |
|
164 * {@link MBeanServer#addNotificationListener(ObjectName, NotificationListener, |
|
165 * NotificationFilter, Object) MBeanServer.addNotificationListener}. If |
|
166 * {@code getDynamicMBeanFor} does not always return the same object for the |
|
167 * same name, more work is needed to make notifications work, as described |
|
168 * <a href="#notifs">below</a>.</p> |
|
169 * |
|
170 * <h4 id="virtual">Namespaces containing Virtual MBeans</h4> |
|
171 * |
|
172 * <p>Virtual MBeans are MBeans that do not exist as Java objects, |
|
173 * except transiently while they are being accessed. This is useful when |
|
174 * there might be very many of them, or when keeping track of their creation |
|
175 * and deletion might be expensive or hard. For example, you might have one |
|
176 * MBean per system process. With an ordinary {@code MBeanServer}, you would |
|
177 * have to list the system processes in order to create an MBean object for |
|
178 * each one, and you would have to track the arrival and departure of system |
|
179 * processes in order to create or delete the corresponding MBeans. With |
|
180 * Virtual MBeans, you only need the MBean for a given process at the exact |
|
181 * point where it is referenced with a call such as |
|
182 * {@link MBeanServer#getAttribute MBeanServer.getAttribute}.</p> |
|
183 * |
|
184 * <p>Here is an example of an {@code MBeanServer} implementation that has |
|
185 * one MBean for every system property. The system property {@code "java.home"} |
|
186 * is represented by the MBean called {@code |
|
187 * com.example:type=Property,name="java.home"}, with an attribute called |
|
188 * {@code Value} that is the value of the property.</p> |
|
189 * |
|
190 * <pre> |
|
191 * public interface PropertyMBean { |
|
192 * public String getValue(); |
|
193 * } |
|
194 * |
|
195 * <a name="PropsMBS"></a>public class PropsMBS extends MBeanServerSupport { |
|
196 * private static ObjectName newObjectName(String name) { |
|
197 * try { |
|
198 * return new ObjectName(name); |
|
199 * } catch (MalformedObjectNameException e) { |
|
200 * throw new AssertionError(e); |
|
201 * } |
|
202 * } |
|
203 * |
|
204 * public static class PropertyImpl implements PropertyMBean { |
|
205 * private final String name; |
|
206 * |
|
207 * public PropertyImpl(String name) { |
|
208 * this.name = name; |
|
209 * } |
|
210 * |
|
211 * public String getValue() { |
|
212 * return System.getProperty(name); |
|
213 * } |
|
214 * } |
|
215 * |
|
216 * @Override |
|
217 * public DynamicMBean {@link #getDynamicMBeanFor |
|
218 * getDynamicMBeanFor}(ObjectName name) |
|
219 * throws InstanceNotFoundException { |
|
220 * |
|
221 * // Check that the name is a legal one for a Property MBean |
|
222 * ObjectName namePattern = newObjectName( |
|
223 * "com.example:type=Property,name=\"*\""); |
|
224 * if (!namePattern.apply(name)) |
|
225 * throw new InstanceNotFoundException(name); |
|
226 * |
|
227 * // Extract the name of the property that the MBean corresponds to |
|
228 * String propName = ObjectName.unquote(name.getKeyProperty("name")); |
|
229 * if (System.getProperty(propName) == null) |
|
230 * throw new InstanceNotFoundException(name); |
|
231 * |
|
232 * // Construct and return a transient MBean object |
|
233 * PropertyMBean propMBean = new PropertyImpl(propName); |
|
234 * return new StandardMBean(propMBean, PropertyMBean.class, false); |
|
235 * } |
|
236 * |
|
237 * @Override |
|
238 * protected {@code Set<ObjectName>} {@link #getNames getNames}() { |
|
239 * {@code Set<ObjectName> names = new TreeSet<ObjectName>();} |
|
240 * Properties props = System.getProperties(); |
|
241 * for (String propName : props.stringPropertyNames()) { |
|
242 * ObjectName objectName = newObjectName( |
|
243 * "com.example:type=Property,name=" + |
|
244 * ObjectName.quote(propName)); |
|
245 * names.add(objectName); |
|
246 * } |
|
247 * return names; |
|
248 * } |
|
249 * } |
|
250 * </pre> |
|
251 * |
|
252 * <p id="virtual-notif-example">Because the {@code getDynamicMBeanFor} method |
|
253 * returns a different object every time it is called, the default handling |
|
254 * of notifications will not work, as explained <a href="#notifs">below</a>. |
|
255 * In this case it does not matter, because the object returned by {@code |
|
256 * getDynamicMBeanFor} is not a {@code NotificationEmitter}, so {@link |
|
257 * MBeanServer#addNotificationListener(ObjectName, NotificationListener, |
|
258 * NotificationFilter, Object) MBeanServer.addNotificationListener} will |
|
259 * always fail. But if we wanted to extend {@code PropsMBS} so that the MBean |
|
260 * for property {@code "foo"} emitted a notification every time that property |
|
261 * changed, we would need to do it as shown below. (Because there is no API to |
|
262 * be informed when a property changes, this code assumes that some other code |
|
263 * calls the {@code propertyChanged} method every time a property changes.)</p> |
|
264 * |
|
265 * <pre> |
|
266 * public class PropsMBS { |
|
267 * ...as <a href="#PropsMBS">above</a>... |
|
268 * |
|
269 * private final {@link VirtualEventManager} vem = new VirtualEventManager(); |
|
270 * |
|
271 * @Override |
|
272 * public NotificationEmitter {@link #getNotificationEmitterFor |
|
273 * getNotificationEmitterFor}( |
|
274 * ObjectName name) throws InstanceNotFoundException { |
|
275 * getDynamicMBeanFor(name); // check that the name is valid |
|
276 * return vem.{@link VirtualEventManager#getNotificationEmitterFor |
|
277 * getNotificationEmitterFor}(name); |
|
278 * } |
|
279 * |
|
280 * public void propertyChanged(String name, String newValue) { |
|
281 * ObjectName objectName = newObjectName( |
|
282 * "com.example:type=Property,name=" + ObjectName.quote(name)); |
|
283 * Notification n = new Notification( |
|
284 * "com.example.property.changed", objectName, 0L, |
|
285 * "Property " + name + " changed"); |
|
286 * n.setUserData(newValue); |
|
287 * vem.{@link VirtualEventManager#publish publish}(objectName, n); |
|
288 * } |
|
289 * } |
|
290 * </pre> |
|
291 * |
|
292 * <h4 id="creation">MBean creation and deletion</h4> |
|
293 * |
|
294 * <p>MBean creation through {@code MBeanServer.createMBean} is disabled |
|
295 * by default. Subclasses which need to support MBean creation |
|
296 * through {@code createMBean} need to implement a single method {@link |
|
297 * #createMBean(String, ObjectName, ObjectName, Object[], String[], |
|
298 * boolean)}.</p> |
|
299 * |
|
300 * <p>Similarly MBean registration and unregistration through {@code |
|
301 * registerMBean} and {@code unregisterMBean} are disabled by default. |
|
302 * Subclasses which need to support MBean registration and |
|
303 * unregistration will need to implement {@link #registerMBean registerMBean} |
|
304 * and {@link #unregisterMBean unregisterMBean}.</p> |
|
305 * |
|
306 * <h4 id="notifs">Notifications</h4> |
|
307 * |
|
308 * <p>By default {@link MBeanServer#addNotificationListener(ObjectName, |
|
309 * NotificationListener, NotificationFilter, Object) addNotificationListener} |
|
310 * is accepted for an MBean <em>{@code name}</em> if {@link #getDynamicMBeanFor |
|
311 * getDynamicMBeanFor}<code>(<em>name</em>)</code> returns an object that is a |
|
312 * {@link NotificationEmitter}. That is appropriate if |
|
313 * {@code getDynamicMBeanFor}<code>(<em>name</em>)</code> always returns the |
|
314 * same object for the same <em>{@code name}</em>. But with |
|
315 * Virtual MBeans, every call to {@code getDynamicMBeanFor} returns a new object, |
|
316 * which is discarded as soon as the MBean request has finished. |
|
317 * So a listener added to that object would be immediately forgotten.</p> |
|
318 * |
|
319 * <p>The simplest way for a subclass that defines Virtual MBeans |
|
320 * to support notifications is to create a private {@link VirtualEventManager} |
|
321 * and override the method {@link |
|
322 * #getNotificationEmitterFor getNotificationEmitterFor} as follows:</p> |
|
323 * |
|
324 * <pre> |
|
325 * private final VirtualEventManager vem = new VirtualEventManager(); |
|
326 * |
|
327 * @Override |
|
328 * public NotificationEmitter getNotificationEmitterFor( |
|
329 * ObjectName name) throws InstanceNotFoundException { |
|
330 * // Check that the name is a valid Virtual MBean. |
|
331 * // This is the easiest way to do that, but not always the |
|
332 * // most efficient: |
|
333 * getDynamicMBeanFor(name); |
|
334 * |
|
335 * // Return an object that supports add/removeNotificationListener |
|
336 * // through the VirtualEventManager. |
|
337 * return vem.getNotificationEmitterFor(name); |
|
338 * } |
|
339 * </pre> |
|
340 * |
|
341 * <p>A notification <em>{@code n}</em> can then be sent from the Virtual MBean |
|
342 * called <em>{@code name}</em> by calling {@link VirtualEventManager#publish |
|
343 * vem.publish}<code>(<em>name</em>, <em>n</em>)</code>. See the example |
|
344 * <a href="#virtual-notif-example">above</a>.</p> |
|
345 * |
|
346 * @since Java SE 7 |
|
347 */ |
|
348 public abstract class MBeanServerSupport implements MBeanServer { |
|
349 |
|
350 /** |
|
351 * A logger for this class. |
|
352 */ |
|
353 private static final Logger LOG = |
|
354 Logger.getLogger(MBeanServerSupport.class.getName()); |
|
355 |
|
356 /** |
|
357 * <p>Make a new {@code MBeanServerSupport} instance.</p> |
|
358 */ |
|
359 protected MBeanServerSupport() { |
|
360 } |
|
361 |
|
362 /** |
|
363 * <p>Returns a dynamically created handle that makes it possible to |
|
364 * access the named MBean for the duration of a method call.</p> |
|
365 * |
|
366 * <p>An easy way to create such a {@link DynamicMBean} handle is, for |
|
367 * instance, to create a temporary MXBean instance and to wrap it in |
|
368 * an instance of |
|
369 * {@link javax.management.StandardMBean}. |
|
370 * This handle should remain valid for the duration of the call |
|
371 * but can then be discarded.</p> |
|
372 * @param name the name of the MBean for which a request was received. |
|
373 * @return a {@link DynamicMBean} handle that can be used to invoke |
|
374 * operations on the named MBean. |
|
375 * @throws InstanceNotFoundException if no such MBean is supposed |
|
376 * to exist. |
|
377 */ |
|
378 public abstract DynamicMBean getDynamicMBeanFor(ObjectName name) |
|
379 throws InstanceNotFoundException; |
|
380 |
|
381 /** |
|
382 * <p>Subclasses should implement this method to return |
|
383 * the names of all MBeans handled by this object instance.</p> |
|
384 * |
|
385 * <p>The object returned by getNames() should be safely {@linkplain |
|
386 * Set#iterator iterable} even in the presence of other threads that may |
|
387 * cause the set of names to change. Typically this means one of the |
|
388 * following:</p> |
|
389 * |
|
390 * <ul> |
|
391 * <li>the returned set of names is always the same; or |
|
392 * <li>the returned set of names is an object such as a {@link |
|
393 * java.util.concurrent.CopyOnWriteArraySet CopyOnWriteArraySet} that is |
|
394 * safely iterable even if the set is changed by other threads; or |
|
395 * <li>a new Set is constructed every time this method is called. |
|
396 * </ul> |
|
397 * |
|
398 * @return the names of all MBeans handled by this object. |
|
399 */ |
|
400 protected abstract Set<ObjectName> getNames(); |
|
401 |
|
402 /** |
|
403 * <p>List names matching the given pattern. |
|
404 * The default implementation of this method calls {@link #getNames()} |
|
405 * and returns the subset of those names matching {@code pattern}.</p> |
|
406 * |
|
407 * @param pattern an ObjectName pattern |
|
408 * @return the list of MBean names that match the given pattern. |
|
409 */ |
|
410 protected Set<ObjectName> getMatchingNames(ObjectName pattern) { |
|
411 return Util.filterMatchingNames(pattern, getNames()); |
|
412 } |
|
413 |
|
414 /** |
|
415 * <p>Returns a {@link NotificationEmitter} which can be used to |
|
416 * subscribe or unsubscribe for notifications with the named |
|
417 * mbean.</p> |
|
418 * |
|
419 * <p>The default implementation of this method calls {@link |
|
420 * #getDynamicMBeanFor getDynamicMBeanFor(name)} and returns that object |
|
421 * if it is a {@code NotificationEmitter}, otherwise null. See <a |
|
422 * href="#notifs">above</a> for further discussion of notification |
|
423 * handling.</p> |
|
424 * |
|
425 * @param name The name of the MBean whose notifications are being |
|
426 * subscribed, or unsuscribed. |
|
427 * |
|
428 * @return A {@link NotificationEmitter} that can be used to subscribe or |
|
429 * unsubscribe for notifications emitted by the named MBean, or {@code |
|
430 * null} if the MBean does not emit notifications and should not be |
|
431 * considered as a {@code NotificationEmitter}. |
|
432 * |
|
433 * @throws InstanceNotFoundException if {@code name} is not the name of |
|
434 * an MBean in this {@code MBeanServer}. |
|
435 */ |
|
436 public NotificationEmitter getNotificationEmitterFor(ObjectName name) |
|
437 throws InstanceNotFoundException { |
|
438 DynamicMBean mbean = getDynamicMBeanFor(name); |
|
439 if (mbean instanceof NotificationEmitter) |
|
440 return (NotificationEmitter) mbean; |
|
441 else |
|
442 return null; |
|
443 } |
|
444 |
|
445 private NotificationEmitter getNonNullNotificationEmitterFor( |
|
446 ObjectName name) |
|
447 throws InstanceNotFoundException { |
|
448 NotificationEmitter emitter = getNotificationEmitterFor(name); |
|
449 if (emitter == null) { |
|
450 IllegalArgumentException iae = new IllegalArgumentException( |
|
451 "Not a NotificationEmitter: " + name); |
|
452 throw new RuntimeOperationsException(iae); |
|
453 } |
|
454 return emitter; |
|
455 } |
|
456 |
|
457 /** |
|
458 * <p>Creates a new MBean in the MBean name space. |
|
459 * This operation is not supported in this base class implementation.</p> |
|
460 * The default implementation of this method always throws an {@link |
|
461 * UnsupportedOperationException} |
|
462 * wrapped in a {@link RuntimeOperationsException}.</p> |
|
463 * |
|
464 * <p>Subclasses may redefine this method to provide an implementation. |
|
465 * All the various flavors of {@code MBeanServer.createMBean} methods |
|
466 * will eventually call this method. A subclass that wishes to |
|
467 * support MBean creation through {@code createMBean} thus only |
|
468 * needs to provide an implementation for this one method. |
|
469 * |
|
470 * @param className The class name of the MBean to be instantiated. |
|
471 * @param name The object name of the MBean. May be null. |
|
472 * @param params An array containing the parameters of the |
|
473 * constructor to be invoked. |
|
474 * @param signature An array containing the signature of the |
|
475 * constructor to be invoked. |
|
476 * @param loaderName The object name of the class loader to be used. |
|
477 * @param useCLR This parameter is {@code true} when this method |
|
478 * is called from one of the {@code MBeanServer.createMBean} methods |
|
479 * whose signature does not include the {@code ObjectName} of an |
|
480 * MBean class loader to use for loading the MBean class. |
|
481 * |
|
482 * @return An <CODE>ObjectInstance</CODE>, containing the |
|
483 * <CODE>ObjectName</CODE> and the Java class name of the newly |
|
484 * instantiated MBean. If the contained <code>ObjectName</code> |
|
485 * is <code>n</code>, the contained Java class name is |
|
486 * <code>{@link javax.management.MBeanServer#getMBeanInfo |
|
487 * getMBeanInfo(n)}.getClassName()</code>. |
|
488 * |
|
489 * @exception ReflectionException Wraps a |
|
490 * <CODE>java.lang.ClassNotFoundException</CODE> or a |
|
491 * <CODE>java.lang.Exception</CODE> that occurred when trying to |
|
492 * invoke the MBean's constructor. |
|
493 * @exception InstanceAlreadyExistsException The MBean is already |
|
494 * under the control of the MBean server. |
|
495 * @exception MBeanRegistrationException The |
|
496 * <CODE>preRegister</CODE> (<CODE>MBeanRegistration</CODE> |
|
497 * interface) method of the MBean has thrown an exception. The |
|
498 * MBean will not be registered. |
|
499 * @exception MBeanException The constructor of the MBean has |
|
500 * thrown an exception |
|
501 * @exception NotCompliantMBeanException This class is not a JMX |
|
502 * compliant MBean |
|
503 * @exception InstanceNotFoundException The specified class loader |
|
504 * is not registered in the MBean server. |
|
505 * @exception RuntimeOperationsException Wraps either: |
|
506 * <ul> |
|
507 * <li>a <CODE>java.lang.IllegalArgumentException</CODE>: The className |
|
508 * passed in parameter is null, the <CODE>ObjectName</CODE> passed in |
|
509 * parameter contains a pattern or no <CODE>ObjectName</CODE> is specified |
|
510 * for the MBean; or</li> |
|
511 * <li>an {@code UnsupportedOperationException} if creating MBeans is not |
|
512 * supported by this {@code MBeanServer} implementation. |
|
513 * </ul> |
|
514 */ |
|
515 public ObjectInstance createMBean(String className, |
|
516 ObjectName name, ObjectName loaderName, Object[] params, |
|
517 String[] signature, boolean useCLR) |
|
518 throws ReflectionException, InstanceAlreadyExistsException, |
|
519 MBeanRegistrationException, MBeanException, |
|
520 NotCompliantMBeanException, InstanceNotFoundException { |
|
521 throw newUnsupportedException("createMBean"); |
|
522 } |
|
523 |
|
524 |
|
525 /** |
|
526 * <p>Attempts to determine whether the named MBean should be |
|
527 * considered as an instance of a given class. The default implementation |
|
528 * of this method calls {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} |
|
529 * to get an MBean object. Then its behaviour is the same as the standard |
|
530 * {@link MBeanServer#isInstanceOf MBeanServer.isInstanceOf} method.</p> |
|
531 * |
|
532 * {@inheritDoc} |
|
533 */ |
|
534 public boolean isInstanceOf(ObjectName name, String className) |
|
535 throws InstanceNotFoundException { |
|
536 |
|
537 final DynamicMBean instance = nonNullMBeanFor(name); |
|
538 |
|
539 try { |
|
540 final String mbeanClassName = instance.getMBeanInfo().getClassName(); |
|
541 |
|
542 if (mbeanClassName.equals(className)) |
|
543 return true; |
|
544 |
|
545 final Object resource; |
|
546 final ClassLoader cl; |
|
547 if (instance instanceof DynamicWrapperMBean) { |
|
548 DynamicWrapperMBean d = (DynamicWrapperMBean) instance; |
|
549 resource = d.getWrappedObject(); |
|
550 cl = d.getWrappedClassLoader(); |
|
551 } else { |
|
552 resource = instance; |
|
553 cl = instance.getClass().getClassLoader(); |
|
554 } |
|
555 |
|
556 final Class<?> classNameClass = Class.forName(className, false, cl); |
|
557 |
|
558 if (classNameClass.isInstance(resource)) |
|
559 return true; |
|
560 |
|
561 if (classNameClass == NotificationBroadcaster.class || |
|
562 classNameClass == NotificationEmitter.class) { |
|
563 try { |
|
564 getNotificationEmitterFor(name); |
|
565 return true; |
|
566 } catch (Exception x) { |
|
567 LOG.finest("MBean " + name + |
|
568 " is not a notification emitter. Ignoring: "+x); |
|
569 return false; |
|
570 } |
|
571 } |
|
572 |
|
573 final Class<?> resourceClass = Class.forName(mbeanClassName, false, cl); |
|
574 return classNameClass.isAssignableFrom(resourceClass); |
|
575 } catch (Exception x) { |
|
576 /* Could be SecurityException or ClassNotFoundException */ |
|
577 LOG.logp(Level.FINEST, |
|
578 MBeanServerSupport.class.getName(), |
|
579 "isInstanceOf", "Exception calling isInstanceOf", x); |
|
580 return false; |
|
581 } |
|
582 } |
|
583 |
|
584 /** |
|
585 * {@inheritDoc} |
|
586 * |
|
587 * <p>The default implementation of this method returns the string |
|
588 * "DefaultDomain".</p> |
|
589 */ |
|
590 public String getDefaultDomain() { |
|
591 return "DefaultDomain"; |
|
592 } |
|
593 |
|
594 /** |
|
595 * {@inheritDoc} |
|
596 * |
|
597 * <p>The default implementation of this method returns |
|
598 * {@link #getNames()}.size().</p> |
|
599 */ |
|
600 public Integer getMBeanCount() { |
|
601 return getNames().size(); |
|
602 } |
|
603 |
|
604 /** |
|
605 * {@inheritDoc} |
|
606 * |
|
607 * <p>The default implementation of this method first calls {@link #getNames |
|
608 * getNames()} to get a list of all MBean names, |
|
609 * and from this set of names, derives the set of domains which contain |
|
610 * MBeans.</p> |
|
611 */ |
|
612 public String[] getDomains() { |
|
613 final Set<ObjectName> names = getNames(); |
|
614 final Set<String> res = new TreeSet<String>(); |
|
615 for (ObjectName n : names) { |
|
616 if (n == null) continue; // not allowed but you never know. |
|
617 res.add(n.getDomain()); |
|
618 } |
|
619 return res.toArray(new String[res.size()]); |
|
620 } |
|
621 |
|
622 |
|
623 /** |
|
624 * {@inheritDoc} |
|
625 * |
|
626 * <p>The default implementation of this method will first |
|
627 * call {@link |
|
628 * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle |
|
629 * to the named MBean, |
|
630 * and then call {@link DynamicMBean#getAttribute getAttribute} |
|
631 * on that {@link DynamicMBean} handle.</p> |
|
632 * |
|
633 * @throws RuntimeOperationsException {@inheritDoc} |
|
634 */ |
|
635 public Object getAttribute(ObjectName name, String attribute) |
|
636 throws MBeanException, AttributeNotFoundException, |
|
637 InstanceNotFoundException, ReflectionException { |
|
638 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
639 return mbean.getAttribute(attribute); |
|
640 } |
|
641 |
|
642 /** |
|
643 * {@inheritDoc} |
|
644 * |
|
645 * <p>The default implementation of this method will first |
|
646 * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} |
|
647 * to obtain a handle to the named MBean, |
|
648 * and then call {@link DynamicMBean#setAttribute setAttribute} |
|
649 * on that {@link DynamicMBean} handle.</p> |
|
650 * |
|
651 * @throws RuntimeOperationsException {@inheritDoc} |
|
652 */ |
|
653 public void setAttribute(ObjectName name, Attribute attribute) |
|
654 throws InstanceNotFoundException, AttributeNotFoundException, |
|
655 InvalidAttributeValueException, MBeanException, |
|
656 ReflectionException { |
|
657 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
658 mbean.setAttribute(attribute); |
|
659 } |
|
660 |
|
661 /** |
|
662 * {@inheritDoc} |
|
663 * |
|
664 * <p>The default implementation of this method will first |
|
665 * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a |
|
666 * handle to the named MBean, |
|
667 * and then call {@link DynamicMBean#getAttributes getAttributes} |
|
668 * on that {@link DynamicMBean} handle.</p> |
|
669 * |
|
670 * @throws RuntimeOperationsException {@inheritDoc} |
|
671 */ |
|
672 public AttributeList getAttributes(ObjectName name, |
|
673 String[] attributes) throws InstanceNotFoundException, |
|
674 ReflectionException { |
|
675 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
676 return mbean.getAttributes(attributes); |
|
677 } |
|
678 |
|
679 /** |
|
680 * {@inheritDoc} |
|
681 * |
|
682 * <p>The default implementation of this method will first |
|
683 * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a |
|
684 * handle to the named MBean, |
|
685 * and then call {@link DynamicMBean#setAttributes setAttributes} |
|
686 * on that {@link DynamicMBean} handle.</p> |
|
687 * |
|
688 * @throws RuntimeOperationsException {@inheritDoc} |
|
689 */ |
|
690 public AttributeList setAttributes(ObjectName name, AttributeList attributes) |
|
691 throws InstanceNotFoundException, ReflectionException { |
|
692 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
693 return mbean.setAttributes(attributes); |
|
694 } |
|
695 |
|
696 /** |
|
697 * {@inheritDoc} |
|
698 * |
|
699 * <p>The default implementation of this method will first |
|
700 * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a |
|
701 * handle to the named MBean, |
|
702 * and then call {@link DynamicMBean#invoke invoke} |
|
703 * on that {@link DynamicMBean} handle.</p> |
|
704 */ |
|
705 public Object invoke(ObjectName name, String operationName, |
|
706 Object[] params, String[] signature) |
|
707 throws InstanceNotFoundException, MBeanException, |
|
708 ReflectionException { |
|
709 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
710 return mbean.invoke(operationName, params, signature); |
|
711 } |
|
712 |
|
713 /** |
|
714 * {@inheritDoc} |
|
715 * |
|
716 * <p>The default implementation of this method will first |
|
717 * call {@link #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a |
|
718 * handle to the named MBean, |
|
719 * and then call {@link DynamicMBean#getMBeanInfo getMBeanInfo} |
|
720 * on that {@link DynamicMBean} handle.</p> |
|
721 */ |
|
722 public MBeanInfo getMBeanInfo(ObjectName name) |
|
723 throws InstanceNotFoundException, IntrospectionException, |
|
724 ReflectionException { |
|
725 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
726 return mbean.getMBeanInfo(); |
|
727 } |
|
728 |
|
729 /** |
|
730 * {@inheritDoc} |
|
731 * |
|
732 * <p>The default implementation of this method will call |
|
733 * {@link #getDynamicMBeanFor getDynamicMBeanFor(name)}.<!-- |
|
734 * -->{@link DynamicMBean#getMBeanInfo getMBeanInfo()}.<!-- |
|
735 * -->{@link MBeanInfo#getClassName getClassName()} to get the |
|
736 * class name to combine with {@code name} to produce a new |
|
737 * {@code ObjectInstance}.</p> |
|
738 */ |
|
739 public ObjectInstance getObjectInstance(ObjectName name) |
|
740 throws InstanceNotFoundException { |
|
741 final DynamicMBean mbean = nonNullMBeanFor(name); |
|
742 final String className = mbean.getMBeanInfo().getClassName(); |
|
743 return new ObjectInstance(name, className); |
|
744 } |
|
745 |
|
746 /** |
|
747 * {@inheritDoc} |
|
748 * |
|
749 * <p>The default implementation of this method will first call {@link |
|
750 * #getDynamicMBeanFor getDynamicMBeanFor(name)} to obtain a handle to the |
|
751 * named MBean. If {@code getDynamicMBeanFor} returns an object, {@code |
|
752 * isRegistered} will return true. If {@code getDynamicMBeanFor} returns |
|
753 * null or throws {@link InstanceNotFoundException}, {@code isRegistered} |
|
754 * will return false.</p> |
|
755 * |
|
756 * @throws RuntimeOperationsException {@inheritDoc} |
|
757 */ |
|
758 public boolean isRegistered(ObjectName name) { |
|
759 try { |
|
760 final DynamicMBean mbean = getDynamicMBeanFor(name); |
|
761 return mbean!=null; |
|
762 } catch (InstanceNotFoundException x) { |
|
763 if (LOG.isLoggable(Level.FINEST)) |
|
764 LOG.finest("MBean "+name+" is not registered: "+x); |
|
765 return false; |
|
766 } |
|
767 } |
|
768 |
|
769 |
|
770 /** |
|
771 * {@inheritDoc} |
|
772 * |
|
773 * <p>The default implementation of this method will first |
|
774 * call {@link #queryNames queryNames} |
|
775 * to get a list of all matching MBeans, and then, for each returned name, |
|
776 * call {@link #getObjectInstance getObjectInstance(name)}.</p> |
|
777 */ |
|
778 public Set<ObjectInstance> queryMBeans(ObjectName pattern, QueryExp query) { |
|
779 final Set<ObjectName> names = queryNames(pattern, query); |
|
780 if (names.isEmpty()) return Collections.emptySet(); |
|
781 final Set<ObjectInstance> mbeans = new HashSet<ObjectInstance>(); |
|
782 for (ObjectName name : names) { |
|
783 try { |
|
784 mbeans.add(getObjectInstance(name)); |
|
785 } catch (SecurityException x) { // DLS: OK |
|
786 continue; |
|
787 } catch (InstanceNotFoundException x) { // DLS: OK |
|
788 continue; |
|
789 } |
|
790 } |
|
791 return mbeans; |
|
792 } |
|
793 |
|
794 /** |
|
795 * {@inheritDoc} |
|
796 * |
|
797 * <p>The default implementation of this method calls {@link #getMatchingNames |
|
798 * getMatchingNames(pattern)} to obtain a list of MBeans matching |
|
799 * the given name pattern. If the {@code query} parameter is null, |
|
800 * this will be the result. Otherwise, it will evaluate the |
|
801 * {@code query} parameter for each of the returned names, exactly |
|
802 * as an {@code MBeanServer} would. This might result in |
|
803 * {@link #getDynamicMBeanFor getDynamicMBeanFor} being called |
|
804 * several times for each returned name.</p> |
|
805 */ |
|
806 public Set<ObjectName> queryNames(ObjectName pattern, QueryExp query) { |
|
807 try { |
|
808 final Set<ObjectName> res = getMatchingNames(pattern); |
|
809 return filterListOfObjectNames(res, query); |
|
810 } catch (Exception x) { |
|
811 LOG.fine("Unexpected exception raised in queryNames: "+x); |
|
812 LOG.log(Level.FINEST, "Unexpected exception raised in queryNames", x); |
|
813 } |
|
814 // We reach here only when an exception was raised. |
|
815 // |
|
816 return Collections.emptySet(); |
|
817 } |
|
818 |
|
819 private final static boolean apply(final QueryExp query, |
|
820 final ObjectName on, |
|
821 final MBeanServer srv) { |
|
822 boolean res = false; |
|
823 MBeanServer oldServer = QueryEval.getMBeanServer(); |
|
824 query.setMBeanServer(srv); |
|
825 try { |
|
826 res = query.apply(on); |
|
827 } catch (Exception e) { |
|
828 LOG.finest("QueryExp.apply threw exception, returning false." + |
|
829 " Cause: "+e); |
|
830 res = false; |
|
831 } finally { |
|
832 /* |
|
833 * query.setMBeanServer is probably |
|
834 * QueryEval.setMBeanServer so put back the old |
|
835 * value. Since that method uses a ThreadLocal |
|
836 * variable, this code is only needed for the |
|
837 * unusual case where the user creates a custom |
|
838 * QueryExp that calls a nested query on another |
|
839 * MBeanServer. |
|
840 */ |
|
841 query.setMBeanServer(oldServer); |
|
842 } |
|
843 return res; |
|
844 } |
|
845 |
|
846 /** |
|
847 * Filters a {@code Set<ObjectName>} according to a pattern and a query. |
|
848 * This might be quite inefficient for virtual name spaces. |
|
849 */ |
|
850 Set<ObjectName> |
|
851 filterListOfObjectNames(Set<ObjectName> list, |
|
852 QueryExp query) { |
|
853 if (list.isEmpty() || query == null) |
|
854 return list; |
|
855 |
|
856 // create a new result set |
|
857 final Set<ObjectName> result = new HashSet<ObjectName>(); |
|
858 |
|
859 for (ObjectName on : list) { |
|
860 // if on doesn't match query exclude it. |
|
861 if (apply(query, on, this)) |
|
862 result.add(on); |
|
863 } |
|
864 return result; |
|
865 } |
|
866 |
|
867 |
|
868 // Don't use {@inheritDoc}, because we don't want to say that the |
|
869 // MBeanServer replaces a reference to the MBean by its ObjectName. |
|
870 /** |
|
871 * <p>Adds a listener to a registered MBean. A notification emitted by |
|
872 * the MBean will be forwarded to the listener.</p> |
|
873 * |
|
874 * <p>This implementation calls |
|
875 * {@link #getNotificationEmitterFor getNotificationEmitterFor} |
|
876 * and invokes {@code addNotificationListener} on the |
|
877 * {@link NotificationEmitter} it returns. |
|
878 * |
|
879 * @see #getDynamicMBeanFor getDynamicMBeanFor |
|
880 * @see #getNotificationEmitterFor getNotificationEmitterFor |
|
881 */ |
|
882 public void addNotificationListener(ObjectName name, |
|
883 NotificationListener listener, NotificationFilter filter, |
|
884 Object handback) throws InstanceNotFoundException { |
|
885 final NotificationEmitter emitter = |
|
886 getNonNullNotificationEmitterFor(name); |
|
887 emitter.addNotificationListener(listener, filter, handback); |
|
888 } |
|
889 |
|
890 /** |
|
891 * {@inheritDoc} |
|
892 * |
|
893 * <p>This implementation calls |
|
894 * {@link #getNotificationEmitterFor getNotificationEmitterFor} |
|
895 * and invokes {@code removeNotificationListener} on the |
|
896 * {@link NotificationEmitter} it returns. |
|
897 * @see #getDynamicMBeanFor getDynamicMBeanFor |
|
898 * @see #getNotificationEmitterFor getNotificationEmitterFor |
|
899 */ |
|
900 public void removeNotificationListener(ObjectName name, |
|
901 NotificationListener listener) |
|
902 throws InstanceNotFoundException, ListenerNotFoundException { |
|
903 final NotificationEmitter emitter = |
|
904 getNonNullNotificationEmitterFor(name); |
|
905 emitter.removeNotificationListener(listener); |
|
906 } |
|
907 |
|
908 /** |
|
909 * {@inheritDoc} |
|
910 * |
|
911 * <p>This implementation calls |
|
912 * {@link #getNotificationEmitterFor getNotificationEmitterFor} |
|
913 * and invokes {@code removeNotificationListener} on the |
|
914 * {@link NotificationEmitter} it returns. |
|
915 * @see #getDynamicMBeanFor getDynamicMBeanFor |
|
916 * @see #getNotificationEmitterFor getNotificationEmitterFor |
|
917 */ |
|
918 public void removeNotificationListener(ObjectName name, |
|
919 NotificationListener listener, NotificationFilter filter, |
|
920 Object handback) |
|
921 throws InstanceNotFoundException, ListenerNotFoundException { |
|
922 NotificationEmitter emitter = |
|
923 getNonNullNotificationEmitterFor(name); |
|
924 emitter.removeNotificationListener(listener); |
|
925 } |
|
926 |
|
927 |
|
928 /** |
|
929 * <p>Adds a listener to a registered MBean.</p> |
|
930 * |
|
931 * <p>The default implementation of this method first calls |
|
932 * {@link #getDynamicMBeanFor getDynamicMBeanFor(listenerName)}. |
|
933 * If that successfully returns an object, call it {@code |
|
934 * mbean}, then (a) if {@code mbean} is an instance of {@link |
|
935 * NotificationListener} then this method calls {@link |
|
936 * #addNotificationListener(ObjectName, NotificationListener, |
|
937 * NotificationFilter, Object) addNotificationListener(name, mbean, filter, |
|
938 * handback)}, otherwise (b) this method throws an exception as specified |
|
939 * for this case.</p> |
|
940 * |
|
941 * <p>This default implementation is not appropriate for Virtual MBeans, |
|
942 * although that only matters if the object returned by {@code |
|
943 * getDynamicMBeanFor} can be an instance of |
|
944 * {@code NotificationListener}.</p> |
|
945 * |
|
946 * @throws RuntimeOperationsException {@inheritDoc} |
|
947 */ |
|
948 public void addNotificationListener(ObjectName name, ObjectName listenerName, |
|
949 NotificationFilter filter, Object handback) |
|
950 throws InstanceNotFoundException { |
|
951 NotificationListener listener = getListenerMBean(listenerName); |
|
952 addNotificationListener(name, listener, filter, handback); |
|
953 } |
|
954 |
|
955 /** |
|
956 * {@inheritDoc} |
|
957 * |
|
958 * <p>This operation is not supported in this base class implementation. |
|
959 * The default implementation of this method always throws |
|
960 * {@link RuntimeOperationsException} wrapping |
|
961 * {@link UnsupportedOperationException}.</p> |
|
962 * |
|
963 * @throws javax.management.RuntimeOperationsException wrapping |
|
964 * {@link UnsupportedOperationException} |
|
965 */ |
|
966 public void removeNotificationListener(ObjectName name, |
|
967 ObjectName listenerName) |
|
968 throws InstanceNotFoundException, ListenerNotFoundException { |
|
969 NotificationListener listener = getListenerMBean(listenerName); |
|
970 removeNotificationListener(name, listener); |
|
971 } |
|
972 |
|
973 /** |
|
974 * {@inheritDoc} |
|
975 * |
|
976 * <p>This operation is not supported in this base class implementation. |
|
977 * The default implementation of this method always throws |
|
978 * {@link RuntimeOperationsException} wrapping |
|
979 * {@link UnsupportedOperationException}.</p> |
|
980 * |
|
981 * @throws javax.management.RuntimeOperationsException wrapping |
|
982 * {@link UnsupportedOperationException} |
|
983 */ |
|
984 public void removeNotificationListener(ObjectName name, |
|
985 ObjectName listenerName, NotificationFilter filter, |
|
986 Object handback) |
|
987 throws InstanceNotFoundException, ListenerNotFoundException { |
|
988 NotificationListener listener = getListenerMBean(listenerName); |
|
989 removeNotificationListener(name, listener, filter, handback); |
|
990 } |
|
991 |
|
992 private NotificationListener getListenerMBean(ObjectName listenerName) |
|
993 throws InstanceNotFoundException { |
|
994 Object mbean = getDynamicMBeanFor(listenerName); |
|
995 if (mbean instanceof NotificationListener) |
|
996 return (NotificationListener) mbean; |
|
997 else { |
|
998 throw newIllegalArgumentException( |
|
999 "MBean is not a NotificationListener: " + listenerName); |
|
1000 } |
|
1001 } |
|
1002 |
|
1003 |
|
1004 /** |
|
1005 * {@inheritDoc} |
|
1006 * |
|
1007 * <p>This operation is not supported in this base class implementation. |
|
1008 * The default implementation of this method always throws |
|
1009 * {@link InstanceNotFoundException} wrapping |
|
1010 * {@link UnsupportedOperationException}.</p> |
|
1011 * |
|
1012 * @return the default implementation of this method never returns. |
|
1013 * @throws javax.management.RuntimeOperationsException wrapping |
|
1014 * {@link UnsupportedOperationException} |
|
1015 */ |
|
1016 public ClassLoader getClassLoader(ObjectName loaderName) |
|
1017 throws InstanceNotFoundException { |
|
1018 final UnsupportedOperationException failed = |
|
1019 new UnsupportedOperationException("getClassLoader"); |
|
1020 final InstanceNotFoundException x = |
|
1021 new InstanceNotFoundException(String.valueOf(loaderName)); |
|
1022 x.initCause(failed); |
|
1023 throw x; |
|
1024 } |
|
1025 |
|
1026 /** |
|
1027 * {@inheritDoc} |
|
1028 * |
|
1029 * <p>The default implementation of this method calls |
|
1030 * {@link #getDynamicMBeanFor getDynamicMBeanFor(mbeanName)} and applies |
|
1031 * the logic just described to the result.</p> |
|
1032 */ |
|
1033 public ClassLoader getClassLoaderFor(ObjectName mbeanName) |
|
1034 throws InstanceNotFoundException { |
|
1035 final DynamicMBean mbean = nonNullMBeanFor(mbeanName); |
|
1036 if (mbean instanceof DynamicWrapperMBean) |
|
1037 return ((DynamicWrapperMBean) mbean).getWrappedClassLoader(); |
|
1038 else |
|
1039 return mbean.getClass().getClassLoader(); |
|
1040 } |
|
1041 |
|
1042 /** |
|
1043 * {@inheritDoc} |
|
1044 * |
|
1045 * <p>The default implementation of this method returns a |
|
1046 * {@link ClassLoaderRepository} containing exactly one loader, |
|
1047 * the {@linkplain Thread#getContextClassLoader() context class loader} |
|
1048 * for the current thread. |
|
1049 * Subclasses can override this method to return a different |
|
1050 * {@code ClassLoaderRepository}.</p> |
|
1051 */ |
|
1052 public ClassLoaderRepository getClassLoaderRepository() { |
|
1053 // We return a new ClassLoaderRepository each time this |
|
1054 // method is called. This is by design, because the |
|
1055 // SingletonClassLoaderRepository is a very small object and |
|
1056 // getClassLoaderRepository() will not be called very often |
|
1057 // (the connector server calls it once) - in the context of |
|
1058 // MBeanServerSupport there's a very good chance that this method will |
|
1059 // *never* be called. |
|
1060 ClassLoader ccl = Thread.currentThread().getContextClassLoader(); |
|
1061 return Util.getSingleClassLoaderRepository(ccl); |
|
1062 } |
|
1063 |
|
1064 |
|
1065 /** |
|
1066 * {@inheritDoc} |
|
1067 * |
|
1068 * <p>This operation is not supported in this base class implementation. |
|
1069 * The default implementation of this method always throws |
|
1070 * {@link RuntimeOperationsException} wrapping |
|
1071 * {@link UnsupportedOperationException}.</p> |
|
1072 * @throws javax.management.RuntimeOperationsException wrapping |
|
1073 * {@link UnsupportedOperationException} |
|
1074 */ |
|
1075 public ObjectInstance registerMBean(Object object, ObjectName name) |
|
1076 throws InstanceAlreadyExistsException, MBeanRegistrationException, |
|
1077 NotCompliantMBeanException { |
|
1078 throw newUnsupportedException("registerMBean"); |
|
1079 } |
|
1080 |
|
1081 /** |
|
1082 * {@inheritDoc} |
|
1083 * |
|
1084 * <p>This operation is not supported in this base class implementation. |
|
1085 * The default implementation of this method always throws |
|
1086 * {@link RuntimeOperationsException} wrapping |
|
1087 * {@link UnsupportedOperationException}. |
|
1088 * @throws javax.management.RuntimeOperationsException wrapping |
|
1089 * {@link UnsupportedOperationException} |
|
1090 */ |
|
1091 public void unregisterMBean(ObjectName name) |
|
1092 throws InstanceNotFoundException, MBeanRegistrationException { |
|
1093 throw newUnsupportedException("unregisterMBean"); |
|
1094 } |
|
1095 |
|
1096 /** |
|
1097 * Calls {@link #createMBean(String, ObjectName, |
|
1098 * ObjectName, Object[], String[], boolean) |
|
1099 * createMBean(className, name, null, params, signature, true)}; |
|
1100 */ |
|
1101 public final ObjectInstance createMBean(String className, ObjectName name, |
|
1102 Object[] params, String[] signature) |
|
1103 throws ReflectionException, InstanceAlreadyExistsException, |
|
1104 MBeanRegistrationException, MBeanException, |
|
1105 NotCompliantMBeanException { |
|
1106 try { |
|
1107 return safeCreateMBean(className, name, null, params, signature, true); |
|
1108 } catch (InstanceNotFoundException ex) { |
|
1109 // should not happen! |
|
1110 throw new MBeanException(ex, "Unexpected exception: " + ex); |
|
1111 } |
|
1112 } |
|
1113 |
|
1114 /** |
|
1115 * Calls {@link #createMBean(String, ObjectName, |
|
1116 * ObjectName, Object[], String[], boolean) |
|
1117 * createMBean(className,name, loaderName, params, signature, false)}; |
|
1118 */ |
|
1119 public final ObjectInstance createMBean(String className, ObjectName name, |
|
1120 ObjectName loaderName, Object[] params, String[] signature) |
|
1121 throws ReflectionException, InstanceAlreadyExistsException, |
|
1122 MBeanRegistrationException, MBeanException, |
|
1123 NotCompliantMBeanException, InstanceNotFoundException { |
|
1124 return safeCreateMBean(className, name, loaderName, params, signature, false); |
|
1125 } |
|
1126 |
|
1127 /** |
|
1128 * Calls {@link #createMBean(String, ObjectName, |
|
1129 * ObjectName, Object[], String[], boolean) |
|
1130 * createMBean(className, name, null, null, null, true)}; |
|
1131 */ |
|
1132 public final ObjectInstance createMBean(String className, ObjectName name) |
|
1133 throws ReflectionException, InstanceAlreadyExistsException, |
|
1134 MBeanRegistrationException, MBeanException, |
|
1135 NotCompliantMBeanException { |
|
1136 try { |
|
1137 return safeCreateMBean(className, name, null, null, null, true); |
|
1138 } catch (InstanceNotFoundException ex) { |
|
1139 // should not happen! |
|
1140 throw new MBeanException(ex, "Unexpected exception: " + ex); |
|
1141 } |
|
1142 } |
|
1143 |
|
1144 /** |
|
1145 * Calls {@link #createMBean(String, ObjectName, |
|
1146 * ObjectName, Object[], String[], boolean) |
|
1147 * createMBean(className, name, loaderName, null, null, false)}; |
|
1148 */ |
|
1149 public final ObjectInstance createMBean(String className, ObjectName name, |
|
1150 ObjectName loaderName) |
|
1151 throws ReflectionException, InstanceAlreadyExistsException, |
|
1152 MBeanRegistrationException, MBeanException, |
|
1153 NotCompliantMBeanException, InstanceNotFoundException { |
|
1154 return safeCreateMBean(className, name, loaderName, null, null, false); |
|
1155 } |
|
1156 |
|
1157 // make sure all exceptions are correctly wrapped in a JMXException |
|
1158 private ObjectInstance safeCreateMBean(String className, |
|
1159 ObjectName name, ObjectName loaderName, Object[] params, |
|
1160 String[] signature, boolean useRepository) |
|
1161 throws ReflectionException, InstanceAlreadyExistsException, |
|
1162 MBeanRegistrationException, MBeanException, |
|
1163 NotCompliantMBeanException, InstanceNotFoundException { |
|
1164 try { |
|
1165 return createMBean(className, name, loaderName, params, |
|
1166 signature, useRepository); |
|
1167 } catch (ReflectionException x) { throw x; |
|
1168 } catch (InstanceAlreadyExistsException x) { throw x; |
|
1169 } catch (MBeanRegistrationException x) { throw x; |
|
1170 } catch (MBeanException x) { throw x; |
|
1171 } catch (NotCompliantMBeanException x) { throw x; |
|
1172 } catch (InstanceNotFoundException x) { throw x; |
|
1173 } catch (SecurityException x) { throw x; |
|
1174 } catch (JMRuntimeException x) { throw x; |
|
1175 } catch (RuntimeException x) { |
|
1176 throw new RuntimeOperationsException(x, x.toString()); |
|
1177 } catch (Exception x) { |
|
1178 throw new MBeanException(x, x.toString()); |
|
1179 } |
|
1180 } |
|
1181 |
|
1182 |
|
1183 /** |
|
1184 * {@inheritDoc} |
|
1185 * |
|
1186 * <p>This operation is not supported in this base class implementation. |
|
1187 * The default implementation of this method always throws |
|
1188 * {@link RuntimeOperationsException} wrapping |
|
1189 * {@link UnsupportedOperationException}.</p> |
|
1190 * |
|
1191 * @throws javax.management.RuntimeOperationsException wrapping |
|
1192 * {@link UnsupportedOperationException} |
|
1193 */ |
|
1194 public Object instantiate(String className) |
|
1195 throws ReflectionException, MBeanException { |
|
1196 throw new UnsupportedOperationException("Not applicable."); |
|
1197 } |
|
1198 |
|
1199 /** |
|
1200 * {@inheritDoc} |
|
1201 * |
|
1202 * <p>This operation is not supported in this base class implementation. |
|
1203 * The default implementation of this method always throws |
|
1204 * {@link RuntimeOperationsException} wrapping |
|
1205 * {@link UnsupportedOperationException}.</p> |
|
1206 * |
|
1207 * @throws javax.management.RuntimeOperationsException wrapping |
|
1208 * {@link UnsupportedOperationException} |
|
1209 */ |
|
1210 public Object instantiate(String className, ObjectName loaderName) |
|
1211 throws ReflectionException, MBeanException, |
|
1212 InstanceNotFoundException { |
|
1213 throw new UnsupportedOperationException("Not applicable."); |
|
1214 } |
|
1215 |
|
1216 /** |
|
1217 * {@inheritDoc} |
|
1218 * |
|
1219 * <p>This operation is not supported in this base class implementation. |
|
1220 * The default implementation of this method always throws |
|
1221 * {@link RuntimeOperationsException} wrapping |
|
1222 * {@link UnsupportedOperationException}.</p> |
|
1223 * |
|
1224 * @throws javax.management.RuntimeOperationsException wrapping |
|
1225 * {@link UnsupportedOperationException} |
|
1226 */ |
|
1227 public Object instantiate(String className, Object[] params, |
|
1228 String[] signature) throws ReflectionException, MBeanException { |
|
1229 throw new UnsupportedOperationException("Not applicable."); |
|
1230 } |
|
1231 |
|
1232 /** |
|
1233 * {@inheritDoc} |
|
1234 * |
|
1235 * <p>This operation is not supported in this base class implementation. |
|
1236 * The default implementation of this method always throws |
|
1237 * {@link RuntimeOperationsException} wrapping |
|
1238 * {@link UnsupportedOperationException}.</p> |
|
1239 * |
|
1240 * @throws javax.management.RuntimeOperationsException wrapping |
|
1241 * {@link UnsupportedOperationException} |
|
1242 */ |
|
1243 public Object instantiate(String className, ObjectName loaderName, |
|
1244 Object[] params, String[] signature) |
|
1245 throws ReflectionException, MBeanException, |
|
1246 InstanceNotFoundException { |
|
1247 throw new UnsupportedOperationException("Not applicable."); |
|
1248 } |
|
1249 |
|
1250 |
|
1251 /** |
|
1252 * {@inheritDoc} |
|
1253 * |
|
1254 * <p>This operation is not supported in this base class implementation. |
|
1255 * The default implementation of this method always throws |
|
1256 * {@link RuntimeOperationsException} wrapping |
|
1257 * {@link UnsupportedOperationException}.</p> |
|
1258 * |
|
1259 * @throws javax.management.RuntimeOperationsException wrapping |
|
1260 * {@link UnsupportedOperationException} |
|
1261 */ |
|
1262 @Deprecated |
|
1263 public ObjectInputStream deserialize(ObjectName name, byte[] data) |
|
1264 throws InstanceNotFoundException, OperationsException { |
|
1265 throw new UnsupportedOperationException("Not applicable."); |
|
1266 } |
|
1267 |
|
1268 /** |
|
1269 * {@inheritDoc} |
|
1270 * |
|
1271 * <p>This operation is not supported in this base class implementation. |
|
1272 * The default implementation of this method always throws |
|
1273 * {@link RuntimeOperationsException} wrapping |
|
1274 * {@link UnsupportedOperationException}.</p> |
|
1275 * |
|
1276 * @throws javax.management.RuntimeOperationsException wrapping |
|
1277 * {@link UnsupportedOperationException} |
|
1278 */ |
|
1279 @Deprecated |
|
1280 public ObjectInputStream deserialize(String className, byte[] data) |
|
1281 throws OperationsException, ReflectionException { |
|
1282 throw new UnsupportedOperationException("Not applicable."); |
|
1283 } |
|
1284 |
|
1285 /** |
|
1286 * {@inheritDoc} |
|
1287 * |
|
1288 * <p>This operation is not supported in this base class implementation. |
|
1289 * The default implementation of this method always throws |
|
1290 * {@link RuntimeOperationsException} wrapping |
|
1291 * {@link UnsupportedOperationException}.</p> |
|
1292 * |
|
1293 * @throws javax.management.RuntimeOperationsException wrapping |
|
1294 * {@link UnsupportedOperationException} |
|
1295 */ |
|
1296 @Deprecated |
|
1297 public ObjectInputStream deserialize(String className, |
|
1298 ObjectName loaderName, byte[] data) |
|
1299 throws InstanceNotFoundException, OperationsException, |
|
1300 ReflectionException { |
|
1301 throw new UnsupportedOperationException("Not applicable."); |
|
1302 } |
|
1303 |
|
1304 |
|
1305 // Calls getDynamicMBeanFor, and throws an InstanceNotFoundException |
|
1306 // if the returned mbean is null. |
|
1307 // The DynamicMBean returned by this method is thus guaranteed to be |
|
1308 // non null. |
|
1309 // |
|
1310 private DynamicMBean nonNullMBeanFor(ObjectName name) |
|
1311 throws InstanceNotFoundException { |
|
1312 if (name == null) |
|
1313 throw newIllegalArgumentException("Null ObjectName"); |
|
1314 if (name.getDomain().equals("")) { |
|
1315 String defaultDomain = getDefaultDomain(); |
|
1316 try { |
|
1317 // XXX change to ObjectName.switchDomain |
|
1318 // current code DOES NOT PRESERVE the order of keys |
|
1319 name = new ObjectName(defaultDomain, name.getKeyPropertyList()); |
|
1320 } catch (Exception e) { |
|
1321 throw newIllegalArgumentException( |
|
1322 "Illegal default domain: " + defaultDomain); |
|
1323 } |
|
1324 } |
|
1325 final DynamicMBean mbean = getDynamicMBeanFor(name); |
|
1326 if (mbean!=null) return mbean; |
|
1327 throw new InstanceNotFoundException(String.valueOf(name)); |
|
1328 } |
|
1329 |
|
1330 static RuntimeException newUnsupportedException(String operation) { |
|
1331 return new RuntimeOperationsException( |
|
1332 new UnsupportedOperationException( |
|
1333 operation+": Not supported in this namespace")); |
|
1334 } |
|
1335 |
|
1336 static RuntimeException newIllegalArgumentException(String msg) { |
|
1337 return new RuntimeOperationsException( |
|
1338 new IllegalArgumentException(msg)); |
|
1339 } |
|
1340 |
|
1341 } |
|