122 * mxbean}</a> field. |
83 * mxbean}</a> field. |
123 */ |
84 */ |
124 public static final String MXBEAN_FIELD = "mxbean"; |
85 public static final String MXBEAN_FIELD = "mxbean"; |
125 |
86 |
126 /** |
87 /** |
127 * The name of the |
|
128 * <a href="Descriptor.html#mxbeanMappingFactoryClass">{@code |
|
129 * mxbeanMappingFactoryClass}</a> field. |
|
130 */ |
|
131 public static final String MXBEAN_MAPPING_FACTORY_CLASS_FIELD = |
|
132 "mxbeanMappingFactoryClass"; |
|
133 |
|
134 /** |
|
135 * The name of the <a href="Descriptor.html#openType">{@code |
88 * The name of the <a href="Descriptor.html#openType">{@code |
136 * openType}</a> field. |
89 * openType}</a> field. |
137 */ |
90 */ |
138 public static final String OPEN_TYPE_FIELD = "openType"; |
91 public static final String OPEN_TYPE_FIELD = "openType"; |
139 |
92 |
140 /** |
93 /** |
141 * The name of the <a href="Descriptor.html#originalType">{@code |
94 * The name of the <a href="Descriptor.html#originalType">{@code |
142 * originalType}</a> field. |
95 * originalType}</a> field. |
143 */ |
96 */ |
144 public static final String ORIGINAL_TYPE_FIELD = "originalType"; |
97 public static final String ORIGINAL_TYPE_FIELD = "originalType"; |
145 |
|
146 /** |
|
147 * The name of the <a href="Descriptor.html#setExceptions">{@code |
|
148 * setExceptions}</a> field. |
|
149 */ |
|
150 public static final String SET_EXCEPTIONS_FIELD = "setExceptions"; |
|
151 |
|
152 /** |
|
153 * The name of the <a href="Descriptor.html#objectNameTemplate">{@code |
|
154 * objectNameTemplate}</a> field. |
|
155 */ |
|
156 public static final String OBJECT_NAME_TEMPLATE = "objectNameTemplate"; |
|
157 |
|
158 /** |
|
159 * <p>Options to apply to an MBean proxy or to an instance of {@link |
|
160 * StandardMBean}.</p> |
|
161 * |
|
162 * <p>For example, to specify the "wrapped object visible" option for a |
|
163 * {@code StandardMBean}, you might write this:</p> |
|
164 * |
|
165 * <pre> |
|
166 * StandardMBean.Options opts = new StandardMBean.Options(); |
|
167 * opts.setWrappedObjectVisible(true); |
|
168 * StandardMBean mbean = new StandardMBean(impl, intf, opts); |
|
169 * </pre> |
|
170 * |
|
171 * @see javax.management.JMX.ProxyOptions |
|
172 * @see javax.management.StandardMBean.Options |
|
173 */ |
|
174 public static class MBeanOptions implements Serializable, Cloneable { |
|
175 private static final long serialVersionUID = -6380842449318177843L; |
|
176 |
|
177 static final MBeanOptions MXBEAN = new MBeanOptions(); |
|
178 static { |
|
179 MXBEAN.setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT); |
|
180 } |
|
181 |
|
182 private MXBeanMappingFactory mappingFactory; |
|
183 |
|
184 /** |
|
185 * <p>Construct an {@code MBeanOptions} object where all options have |
|
186 * their default values.</p> |
|
187 */ |
|
188 public MBeanOptions() {} |
|
189 |
|
190 @Override |
|
191 public MBeanOptions clone() { |
|
192 try { |
|
193 return (MBeanOptions) super.clone(); |
|
194 } catch (CloneNotSupportedException e) { |
|
195 throw new AssertionError(e); |
|
196 } |
|
197 } |
|
198 |
|
199 /** |
|
200 * <p>True if this is an MXBean proxy or a StandardMBean instance |
|
201 * that is an MXBean. The default value is false.</p> |
|
202 * |
|
203 * <p>This method is equivalent to {@link #getMXBeanMappingFactory() |
|
204 * this.getMXBeanMappingFactory()}{@code != null}.</p> |
|
205 * |
|
206 * @return true if this is an MXBean proxy or a StandardMBean instance |
|
207 * that is an MXBean. |
|
208 */ |
|
209 public boolean isMXBean() { |
|
210 return (this.mappingFactory != null); |
|
211 } |
|
212 |
|
213 /** |
|
214 * <p>The mappings between Java types and Open Types to be used in |
|
215 * an MXBean proxy or a StandardMBean instance that is an MXBean, |
|
216 * or null if this instance is not for an MXBean. |
|
217 * The default value is null.</p> |
|
218 * |
|
219 * @return the mappings to be used in this proxy or StandardMBean, |
|
220 * or null if this instance is not for an MXBean. |
|
221 */ |
|
222 public MXBeanMappingFactory getMXBeanMappingFactory() { |
|
223 return mappingFactory; |
|
224 } |
|
225 |
|
226 /** |
|
227 * <p>Set the {@link #getMXBeanMappingFactory() MXBeanMappingFactory} to |
|
228 * the given value. The value should be null if this instance is not |
|
229 * for an MXBean. If this instance is for an MXBean, the value should |
|
230 * usually be either a custom mapping factory, or |
|
231 * {@link MXBeanMappingFactory#forInterface |
|
232 * MXBeanMappingFactory.forInterface}{@code (mxbeanInterface)} |
|
233 * which signifies |
|
234 * that the {@linkplain MXBeanMappingFactory#DEFAULT default} mapping |
|
235 * factory should be used unless an {@code @}{@link |
|
236 * javax.management.openmbean.MXBeanMappingFactoryClass |
|
237 * MXBeanMappingFactoryClass} annotation on {@code mxbeanInterface} |
|
238 * specifies otherwise.</p> |
|
239 * |
|
240 * <p>Examples:</p> |
|
241 * <pre> |
|
242 * MBeanOptions opts = new MBeanOptions(); |
|
243 * opts.setMXBeanMappingFactory(myMappingFactory); |
|
244 * MyMXBean proxy = JMX.newMBeanProxy( |
|
245 * mbeanServerConnection, objectName, MyMXBean.class, opts); |
|
246 * |
|
247 * // ...or... |
|
248 * |
|
249 * MBeanOptions opts = new MBeanOptions(); |
|
250 * MXBeanMappingFactory defaultFactoryForMyMXBean = |
|
251 * MXBeanMappingFactory.forInterface(MyMXBean.class); |
|
252 * opts.setMXBeanMappingFactory(defaultFactoryForMyMXBean); |
|
253 * MyMXBean proxy = JMX.newMBeanProxy( |
|
254 * mbeanServerConnection, objectName, MyMXBean.class, opts); |
|
255 * </pre> |
|
256 * |
|
257 * @param f the new value. If null, this instance is not for an |
|
258 * MXBean. |
|
259 */ |
|
260 public void setMXBeanMappingFactory(MXBeanMappingFactory f) { |
|
261 this.mappingFactory = f; |
|
262 } |
|
263 |
|
264 /* To maximise object sharing, classes in this package can replace |
|
265 * a private MBeanOptions with no MXBeanMappingFactory with one |
|
266 * of these shared instances. But they must be EXTREMELY careful |
|
267 * never to give out the shared instances to user code, which could |
|
268 * modify them. |
|
269 */ |
|
270 private static final MBeanOptions[] CANONICALS = { |
|
271 new MBeanOptions(), MXBEAN, |
|
272 }; |
|
273 // Overridden in local subclasses: |
|
274 MBeanOptions[] canonicals() { |
|
275 return CANONICALS; |
|
276 } |
|
277 |
|
278 // This is only used by the logic for canonical instances. |
|
279 // Overridden in local subclasses: |
|
280 boolean same(MBeanOptions opt) { |
|
281 return (opt.mappingFactory == mappingFactory); |
|
282 } |
|
283 |
|
284 final MBeanOptions canonical() { |
|
285 for (MBeanOptions opt : canonicals()) { |
|
286 if (opt.getClass() == this.getClass() && same(opt)) |
|
287 return opt; |
|
288 } |
|
289 return this; |
|
290 } |
|
291 |
|
292 final MBeanOptions uncanonical() { |
|
293 for (MBeanOptions opt : canonicals()) { |
|
294 if (this == opt) |
|
295 return clone(); |
|
296 } |
|
297 return this; |
|
298 } |
|
299 |
|
300 private Map<String, Object> toMap() { |
|
301 Map<String, Object> map = new TreeMap<String, Object>(); |
|
302 try { |
|
303 BeanInfo bi = java.beans.Introspector.getBeanInfo(getClass()); |
|
304 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); |
|
305 for (PropertyDescriptor pd : pds) { |
|
306 String name = pd.getName(); |
|
307 if (name.equals("class")) |
|
308 continue; |
|
309 Method get = pd.getReadMethod(); |
|
310 if (get != null) |
|
311 map.put(name, get.invoke(this)); |
|
312 } |
|
313 } catch (Exception e) { |
|
314 Throwable t = e; |
|
315 if (t instanceof InvocationTargetException) |
|
316 t = t.getCause(); |
|
317 map.put("Exception", t); |
|
318 } |
|
319 return map; |
|
320 } |
|
321 |
|
322 @Override |
|
323 public String toString() { |
|
324 return getClass().getSimpleName() + toMap(); |
|
325 // For example "MBeanOptions{MXBean=true, <etc>}". |
|
326 } |
|
327 |
|
328 /** |
|
329 * <p>Indicates whether some other object is "equal to" this one. The |
|
330 * result is true if and only if the other object is also an instance |
|
331 * of MBeanOptions or a subclass, and has the same properties with |
|
332 * the same values.</p> |
|
333 * @return {@inheritDoc} |
|
334 */ |
|
335 @Override |
|
336 public boolean equals(Object obj) { |
|
337 if (obj == this) |
|
338 return true; |
|
339 if (obj == null || obj.getClass() != this.getClass()) |
|
340 return false; |
|
341 return toMap().equals(((MBeanOptions) obj).toMap()); |
|
342 } |
|
343 |
|
344 @Override |
|
345 public int hashCode() { |
|
346 return toMap().hashCode(); |
|
347 } |
|
348 } |
|
349 |
|
350 /** |
|
351 * <p>Options to apply to an MBean proxy.</p> |
|
352 * |
|
353 * @see #newMBeanProxy |
|
354 */ |
|
355 public static class ProxyOptions extends MBeanOptions { |
|
356 private static final long serialVersionUID = 7238804866098386559L; |
|
357 |
|
358 private boolean notificationEmitter; |
|
359 |
|
360 /** |
|
361 * <p>Construct a {@code ProxyOptions} object where all options have |
|
362 * their default values.</p> |
|
363 */ |
|
364 public ProxyOptions() {} |
|
365 |
|
366 @Override |
|
367 public ProxyOptions clone() { |
|
368 return (ProxyOptions) super.clone(); |
|
369 } |
|
370 |
|
371 /** |
|
372 * <p>Defines whether the returned proxy should |
|
373 * implement {@link NotificationEmitter}. The default value is false.</p> |
|
374 * |
|
375 * @return true if this proxy will be a NotificationEmitter. |
|
376 * |
|
377 * @see JMX#newMBeanProxy(MBeanServerConnection, ObjectName, Class, |
|
378 * MBeanOptions) |
|
379 */ |
|
380 public boolean isNotificationEmitter() { |
|
381 return this.notificationEmitter; |
|
382 } |
|
383 |
|
384 /** |
|
385 * <p>Set the {@link #isNotificationEmitter NotificationEmitter} option to |
|
386 * the given value.</p> |
|
387 * @param emitter the new value. |
|
388 */ |
|
389 public void setNotificationEmitter(boolean emitter) { |
|
390 this.notificationEmitter = emitter; |
|
391 } |
|
392 |
|
393 // Canonical objects for each of (MXBean,!MXBean) x (Emitter,!Emitter) |
|
394 private static final ProxyOptions[] CANONICALS = { |
|
395 new ProxyOptions(), new ProxyOptions(), |
|
396 new ProxyOptions(), new ProxyOptions(), |
|
397 }; |
|
398 static { |
|
399 CANONICALS[1].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT); |
|
400 CANONICALS[2].setNotificationEmitter(true); |
|
401 CANONICALS[3].setMXBeanMappingFactory(MXBeanMappingFactory.DEFAULT); |
|
402 CANONICALS[3].setNotificationEmitter(true); |
|
403 } |
|
404 @Override |
|
405 MBeanOptions[] canonicals() { |
|
406 return CANONICALS; |
|
407 } |
|
408 |
|
409 @Override |
|
410 boolean same(MBeanOptions opt) { |
|
411 return (super.same(opt) && opt instanceof ProxyOptions && |
|
412 ((ProxyOptions) opt).notificationEmitter == notificationEmitter); |
|
413 } |
|
414 } |
|
415 |
98 |
416 /** |
99 /** |
417 * <p>Make a proxy for a Standard MBean in a local or remote |
100 * <p>Make a proxy for a Standard MBean in a local or remote |
418 * MBean Server.</p> |
101 * MBean Server.</p> |
419 * |
102 * |
499 * MBeanServerConnection#addNotificationListener(ObjectName, |
182 * MBeanServerConnection#addNotificationListener(ObjectName, |
500 * NotificationListener, NotificationFilter, Object)}, and |
183 * NotificationListener, NotificationFilter, Object)}, and |
501 * likewise for the other methods of {@link |
184 * likewise for the other methods of {@link |
502 * NotificationBroadcaster} and {@link NotificationEmitter}.</p> |
185 * NotificationBroadcaster} and {@link NotificationEmitter}.</p> |
503 * |
186 * |
504 * <p>This method is equivalent to {@link |
|
505 * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions) |
|
506 * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where |
|
507 * {@code opts} is a {@link JMX.ProxyOptions} representing the |
|
508 * {@code notificationEmitter} parameter.</p> |
|
509 * |
|
510 * @param connection the MBean server to forward to. |
187 * @param connection the MBean server to forward to. |
511 * @param objectName the name of the MBean within |
188 * @param objectName the name of the MBean within |
512 * {@code connection} to forward to. |
189 * {@code connection} to forward to. |
513 * @param interfaceClass the management interface that the MBean |
190 * @param interfaceClass the management interface that the MBean |
514 * exports, which will also be implemented by the returned proxy. |
191 * exports, which will also be implemented by the returned proxy. |
515 * @param notificationEmitter make the returned proxy |
192 * @param notificationEmitter make the returned proxy |
516 * implement {@link NotificationEmitter} by forwarding its methods |
193 * implement {@link NotificationEmitter} by forwarding its methods |
517 * via {@code connection}. |
194 * via {@code connection}. |
|
195 * |
518 * @param <T> allows the compiler to know that if the {@code |
196 * @param <T> allows the compiler to know that if the {@code |
519 * interfaceClass} parameter is {@code MyMBean.class}, for |
197 * interfaceClass} parameter is {@code MyMBean.class}, for |
520 * example, then the return type is {@code MyMBean}. |
198 * example, then the return type is {@code MyMBean}. |
|
199 * |
521 * @return the new proxy instance. |
200 * @return the new proxy instance. |
522 */ |
201 */ |
523 public static <T> T newMBeanProxy(MBeanServerConnection connection, |
202 public static <T> T newMBeanProxy(MBeanServerConnection connection, |
524 ObjectName objectName, |
203 ObjectName objectName, |
525 Class<T> interfaceClass, |
204 Class<T> interfaceClass, |
526 boolean notificationEmitter) { |
205 boolean notificationEmitter) { |
527 ProxyOptions opts = new ProxyOptions(); |
206 return MBeanServerInvocationHandler.newProxyInstance( |
528 opts.setNotificationEmitter(notificationEmitter); |
207 connection, |
529 return newMBeanProxy(connection, objectName, interfaceClass, opts); |
208 objectName, |
|
209 interfaceClass, |
|
210 notificationEmitter); |
530 } |
211 } |
531 |
212 |
532 /** |
213 /** |
533 * <p>Make a proxy for an MXBean in a local or remote |
214 * <p>Make a proxy for an MXBean in a local or remote |
534 * MBean Server.</p> |
215 * MBean Server.</p> |
639 * MBeanServerConnection#addNotificationListener(ObjectName, |
324 * MBeanServerConnection#addNotificationListener(ObjectName, |
640 * NotificationListener, NotificationFilter, Object)}, and |
325 * NotificationListener, NotificationFilter, Object)}, and |
641 * likewise for the other methods of {@link |
326 * likewise for the other methods of {@link |
642 * NotificationBroadcaster} and {@link NotificationEmitter}.</p> |
327 * NotificationBroadcaster} and {@link NotificationEmitter}.</p> |
643 * |
328 * |
644 * <p>This method is equivalent to {@link |
|
645 * #newMBeanProxy(MBeanServerConnection, ObjectName, Class, JMX.MBeanOptions) |
|
646 * newMBeanProxy(connection, objectName, interfaceClass, opts)}, where |
|
647 * {@code opts} is a {@link JMX.ProxyOptions} where the {@link |
|
648 * JMX.ProxyOptions#getMXBeanMappingFactory() MXBeanMappingFactory} |
|
649 * property is |
|
650 * {@link MXBeanMappingFactory#forInterface(Class) |
|
651 * MXBeanMappingFactory.forInterface(interfaceClass)} and the {@link |
|
652 * JMX.ProxyOptions#isNotificationEmitter() notificationEmitter} property |
|
653 * is equal to the {@code notificationEmitter} parameter.</p> |
|
654 * |
|
655 * @param connection the MBean server to forward to. |
329 * @param connection the MBean server to forward to. |
656 * @param objectName the name of the MBean within |
330 * @param objectName the name of the MBean within |
657 * {@code connection} to forward to. |
331 * {@code connection} to forward to. |
658 * @param interfaceClass the MXBean interface, |
332 * @param interfaceClass the MXBean interface, |
659 * which will also be implemented by the returned proxy. |
333 * which will also be implemented by the returned proxy. |
660 * @param notificationEmitter make the returned proxy |
334 * @param notificationEmitter make the returned proxy |
661 * implement {@link NotificationEmitter} by forwarding its methods |
335 * implement {@link NotificationEmitter} by forwarding its methods |
662 * via {@code connection}. |
336 * via {@code connection}. |
|
337 * |
663 * @param <T> allows the compiler to know that if the {@code |
338 * @param <T> allows the compiler to know that if the {@code |
664 * interfaceClass} parameter is {@code MyMXBean.class}, for |
339 * interfaceClass} parameter is {@code MyMXBean.class}, for |
665 * example, then the return type is {@code MyMXBean}. |
340 * example, then the return type is {@code MyMXBean}. |
|
341 * |
666 * @return the new proxy instance. |
342 * @return the new proxy instance. |
667 */ |
343 */ |
668 public static <T> T newMXBeanProxy(MBeanServerConnection connection, |
344 public static <T> T newMXBeanProxy(MBeanServerConnection connection, |
669 ObjectName objectName, |
345 ObjectName objectName, |
670 Class<T> interfaceClass, |
346 Class<T> interfaceClass, |
671 boolean notificationEmitter) { |
347 boolean notificationEmitter) { |
672 ProxyOptions opts = new ProxyOptions(); |
348 // Check interface for MXBean compliance |
673 MXBeanMappingFactory f = MXBeanMappingFactory.forInterface(interfaceClass); |
349 // |
674 opts.setMXBeanMappingFactory(f); |
|
675 opts.setNotificationEmitter(notificationEmitter); |
|
676 return newMBeanProxy(connection, objectName, interfaceClass, opts); |
|
677 } |
|
678 |
|
679 /** |
|
680 * <p>Make a proxy for a Standard MBean or MXBean in a local or remote MBean |
|
681 * Server that may also support the methods of {@link |
|
682 * NotificationEmitter} and (for an MXBean) that may define custom MXBean |
|
683 * type mappings.</p> |
|
684 * |
|
685 * <p>This method behaves the same as |
|
686 * {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class)} or |
|
687 * {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class)}, |
|
688 * according as {@code opts.isMXBean()} is respectively false or true; but |
|
689 * with the following changes based on {@code opts}.</p> |
|
690 * |
|
691 * <ul> |
|
692 * <li>If {@code opts.isNotificationEmitter()} is {@code |
|
693 * true}, then the MBean is assumed to be a {@link |
|
694 * NotificationBroadcaster} or {@link NotificationEmitter} and the |
|
695 * returned proxy will implement {@link NotificationEmitter} as |
|
696 * well as {@code interfaceClass}. A call to {@link |
|
697 * NotificationBroadcaster#addNotificationListener} on the proxy |
|
698 * will result in a call to {@link |
|
699 * MBeanServerConnection#addNotificationListener(ObjectName, |
|
700 * NotificationListener, NotificationFilter, Object)}, and |
|
701 * likewise for the other methods of {@link |
|
702 * NotificationBroadcaster} and {@link NotificationEmitter}.</li> |
|
703 * |
|
704 * <li>If {@code opts.getMXBeanMappingFactory()} is not null, |
|
705 * then the mappings it defines will be applied to convert between |
|
706 * arbitrary Java types and Open Types.</li> |
|
707 * </ul> |
|
708 * |
|
709 * <p>The object returned by this method is a |
|
710 * {@link Proxy} whose {@code InvocationHandler} is an |
|
711 * {@link MBeanServerInvocationHandler}. This means that it is possible |
|
712 * to retrieve the parameters that were used to produce the proxy. If the |
|
713 * proxy was produced as follows...</p> |
|
714 * |
|
715 * <pre> |
|
716 * FooMBean proxy = |
|
717 * JMX.newMBeanProxy(connection, objectName, FooMBean.class, opts); |
|
718 * </pre> |
|
719 * |
|
720 * <p>...then you can get the {@code MBeanServerInvocationHandler} like |
|
721 * this...</p> |
|
722 * |
|
723 * <pre> |
|
724 * MBeanServerInvocationHandler mbsih = (MBeanServerInvocationHandler) |
|
725 * {@link Proxy#getInvocationHandler(Object) |
|
726 * Proxy.getInvocationHandler}(proxy); |
|
727 * </pre> |
|
728 * |
|
729 * <p>...and you can retrieve {@code connection}, {@code |
|
730 * objectName}, and {@code opts} using the {@link |
|
731 * MBeanServerInvocationHandler#getMBeanServerConnection() |
|
732 * getMBeanServerConnection()}, {@link |
|
733 * MBeanServerInvocationHandler#getObjectName() getObjectName()}, and |
|
734 * {@link MBeanServerInvocationHandler#getMBeanOptions() getMBeanOptions()} |
|
735 * methods on {@code mbsih}. You can retrieve {@code FooMBean.class} |
|
736 * using {@code proxy.getClass().}{@link |
|
737 * Class#getInterfaces() getInterfaces()}.</p> |
|
738 * |
|
739 * @param connection the MBean server to forward to. |
|
740 * @param objectName the name of the MBean within |
|
741 * {@code connection} to forward to. |
|
742 * @param interfaceClass the Standard MBean or MXBean interface, |
|
743 * which will also be implemented by the returned proxy. |
|
744 * @param opts the options to apply for this proxy. Can be null, |
|
745 * in which case default options are applied. |
|
746 * @param <T> allows the compiler to know that if the {@code |
|
747 * interfaceClass} parameter is {@code MyMXBean.class}, for |
|
748 * example, then the return type is {@code MyMXBean}. |
|
749 * @return the new proxy instance. |
|
750 * |
|
751 * @throws IllegalArgumentException if {@code interfaceClass} is not a |
|
752 * valid MXBean interface. |
|
753 */ |
|
754 public static <T> T newMBeanProxy(MBeanServerConnection connection, |
|
755 ObjectName objectName, |
|
756 Class<T> interfaceClass, |
|
757 MBeanOptions opts) { |
|
758 try { |
350 try { |
759 return newMBeanProxy2(connection, objectName, interfaceClass, opts); |
351 Introspector.testComplianceMXBeanInterface(interfaceClass); |
760 } catch (NotCompliantMBeanException e) { |
352 } catch (NotCompliantMBeanException e) { |
761 throw new IllegalArgumentException(e); |
353 throw new IllegalArgumentException(e); |
762 } |
354 } |
763 } |
|
764 |
|
765 private static <T> T newMBeanProxy2(MBeanServerConnection connection, |
|
766 ObjectName objectName, |
|
767 Class<T> interfaceClass, |
|
768 MBeanOptions opts) |
|
769 throws NotCompliantMBeanException { |
|
770 |
|
771 if (opts == null) |
|
772 opts = new MBeanOptions(); |
|
773 |
|
774 boolean notificationEmitter = opts instanceof ProxyOptions && |
|
775 ((ProxyOptions) opts).isNotificationEmitter(); |
|
776 |
|
777 MXBeanMappingFactory mappingFactory = opts.getMXBeanMappingFactory(); |
|
778 |
|
779 if (mappingFactory != null) { |
|
780 // Check interface for MXBean compliance |
|
781 Introspector.testComplianceMXBeanInterface(interfaceClass, |
|
782 mappingFactory); |
|
783 } |
|
784 |
|
785 InvocationHandler handler = new MBeanServerInvocationHandler( |
355 InvocationHandler handler = new MBeanServerInvocationHandler( |
786 connection, objectName, opts); |
356 connection, objectName, true); |
787 final Class<?>[] interfaces; |
357 final Class<?>[] interfaces; |
788 if (notificationEmitter) { |
358 if (notificationEmitter) { |
789 interfaces = |
359 interfaces = |
790 new Class<?>[] {interfaceClass, NotificationEmitter.class}; |
360 new Class<?>[] {interfaceClass, NotificationEmitter.class}; |
791 } else |
361 } else |
820 return interfaceClass.getName().endsWith("MXBean"); |
390 return interfaceClass.getName().endsWith("MXBean"); |
821 // We don't bother excluding the case where the name is |
391 // We don't bother excluding the case where the name is |
822 // exactly the string "MXBean" since that would mean there |
392 // exactly the string "MXBean" since that would mean there |
823 // was no package name, which is pretty unlikely in practice. |
393 // was no package name, which is pretty unlikely in practice. |
824 } |
394 } |
825 |
|
826 /** |
|
827 * <p>Test if an MBean can emit notifications. An MBean can emit |
|
828 * notifications if either it implements {@link NotificationBroadcaster} |
|
829 * (perhaps through its child interface {@link NotificationEmitter}), or |
|
830 * it uses <a href="MBeanRegistration.html#injection">resource |
|
831 * injection</a> to obtain an instance of {@link SendNotification} |
|
832 * through which it can send notifications.</p> |
|
833 * |
|
834 * @param mbean an MBean object. |
|
835 * @return true if the given object is a valid MBean that can emit |
|
836 * notifications; false if the object is a valid MBean but that |
|
837 * cannot emit notifications. |
|
838 * @throws NotCompliantMBeanException if the given object is not |
|
839 * a valid MBean. |
|
840 */ |
|
841 public static boolean isNotificationSource(Object mbean) |
|
842 throws NotCompliantMBeanException { |
|
843 for (int i = 0; i < 2; i++) { |
|
844 if (mbean instanceof NotificationBroadcaster || |
|
845 MBeanInjector.injectsSendNotification(mbean)) |
|
846 return true; |
|
847 if (mbean instanceof DynamicWrapperMBean) |
|
848 mbean = ((DynamicWrapperMBean) mbean).getWrappedObject(); |
|
849 else |
|
850 break; |
|
851 } |
|
852 return false; |
|
853 } |
|
854 |
|
855 /** |
|
856 * <p>Return the version of the JMX specification that a (possibly remote) |
|
857 * MBean Server is using. The JMX specification described in this |
|
858 * documentation is version 2.0. The earlier versions that might be |
|
859 * reported by this method are 1.0, 1.1, 1.2, and 1.4. (There is no 1.3.) |
|
860 * All of these versions and all future versions can be compared using |
|
861 * {@link String#compareTo(String)}. So, for example, to tell if |
|
862 * {@code mbsc} is running at least version 2.0 you can write:</p> |
|
863 * |
|
864 * <pre> |
|
865 * String version = JMX.getSpecificationVersion(mbsc, null); |
|
866 * boolean atLeast2dot0 = (version.compareTo("2.0") >= 0); |
|
867 * </pre> |
|
868 * |
|
869 * <p>A remote MBean Server might be running an earlier version of the |
|
870 * JMX API, and in that case <a href="package-summary.html#interop">certain |
|
871 * features</a> might not be available in it.</p> |
|
872 * |
|
873 * <p>The version of the MBean Server {@code mbsc} is not necessarily |
|
874 * the version of all namespaces within that MBean Server, for example |
|
875 * if some of them use {@link javax.management.namespace.JMXRemoteNamespace |
|
876 * JMXRemoteNamespace}. To determine the version of the namespace |
|
877 * that a particular MBean is in, give its name as the {@code mbeanName} |
|
878 * parameter.</p> |
|
879 * |
|
880 * @param mbsc a connection to an MBean Server. |
|
881 * |
|
882 * @param mbeanName the name of an MBean within that MBean Server, or null. |
|
883 * If non-null, the namespace of this name, as determined by |
|
884 * {@link JMXNamespaces#getContainingNamespace |
|
885 * JMXNamespaces.getContainingNamespace}, is the one whose specification |
|
886 * version will be returned. |
|
887 * |
|
888 * @return the JMX specification version reported by that MBean Server. |
|
889 * |
|
890 * @throws IllegalArgumentException if {@code mbsc} is null, or if |
|
891 * {@code mbeanName} includes a wildcard character ({@code *} or {@code ?}) |
|
892 * in its namespace. |
|
893 * |
|
894 * @throws IOException if the version cannot be obtained, either because |
|
895 * there is a communication problem or because the remote MBean Server |
|
896 * does not have the appropriate {@linkplain |
|
897 * MBeanServerDelegateMBean#getSpecificationVersion() attribute}. |
|
898 * |
|
899 * @see <a href="package-summary.html#interop">Interoperability between |
|
900 * versions of the JMX specification</a> |
|
901 * @see MBeanServerDelegateMBean#getSpecificationVersion |
|
902 */ |
|
903 public static String getSpecificationVersion( |
|
904 MBeanServerConnection mbsc, ObjectName mbeanName) |
|
905 throws IOException { |
|
906 if (mbsc == null) |
|
907 throw new IllegalArgumentException("Null MBeanServerConnection"); |
|
908 |
|
909 String namespace; |
|
910 if (mbeanName == null) |
|
911 namespace = ""; |
|
912 else |
|
913 namespace = JMXNamespaces.getContainingNamespace(mbeanName); |
|
914 if (namespace.contains("*") || namespace.contains("?")) { |
|
915 throw new IllegalArgumentException( |
|
916 "ObjectName contains namespace wildcard: " + mbeanName); |
|
917 } |
|
918 |
|
919 try { |
|
920 if (namespace.length() > 0) |
|
921 mbsc = JMXNamespaces.narrowToNamespace(mbsc, namespace); |
|
922 return (String) mbsc.getAttribute( |
|
923 MBeanServerDelegate.DELEGATE_NAME, "SpecificationVersion"); |
|
924 } catch (IOException e) { |
|
925 throw e; |
|
926 } catch (Exception e) { |
|
927 throw new IOException(e); |
|
928 } |
|
929 } |
|
930 } |
395 } |