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