History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java+2064−0
@@ -0,0 +1,2064 @@
1/*
2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.jmx.interceptor;
27
28
29// JMX RI
30import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
31import com.sun.jmx.mbeanserver.DynamicMBean2;
32import com.sun.jmx.mbeanserver.Introspector;
33import com.sun.jmx.mbeanserver.MBeanInstantiator;
34import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
35import com.sun.jmx.mbeanserver.NamedObject;
36import com.sun.jmx.mbeanserver.Repository;
37import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
38import com.sun.jmx.mbeanserver.Util;
39import com.sun.jmx.remote.util.EnvHelp;
40
41import java.io.ObjectInputStream;
42import java.lang.ref.WeakReference;
43import java.security.AccessControlContext;
44import java.security.AccessController;
45import java.security.Permission;
46import java.security.PrivilegedAction;
47import java.security.ProtectionDomain;
48import java.util.ArrayList;
49import java.util.HashSet;
50import java.util.List;
51import java.util.Set;
52import java.util.WeakHashMap;
53import java.util.logging.Level;
54
55// JMX import
56import javax.management.Attribute;
57import javax.management.AttributeList;
58import javax.management.AttributeNotFoundException;
59import javax.management.DynamicMBean;
60import javax.management.InstanceAlreadyExistsException;
61import javax.management.InstanceNotFoundException;
62import javax.management.IntrospectionException;
63import javax.management.InvalidAttributeValueException;
64import javax.management.JMRuntimeException;
65import javax.management.ListenerNotFoundException;
66import javax.management.MBeanException;
67import javax.management.MBeanInfo;
68import javax.management.MBeanPermission;
69import javax.management.MBeanRegistration;
70import javax.management.MBeanRegistrationException;
71import javax.management.MBeanServer;
72import javax.management.MBeanServerDelegate;
73import javax.management.MBeanServerNotification;
74import javax.management.MBeanTrustPermission;
75import javax.management.NotCompliantMBeanException;
76import javax.management.Notification;
77import javax.management.NotificationBroadcaster;
78import javax.management.NotificationEmitter;
79import javax.management.NotificationFilter;
80import javax.management.NotificationListener;
81import javax.management.ObjectInstance;
82import javax.management.ObjectName;
83import javax.management.OperationsException;
84import javax.management.QueryEval;
85import javax.management.QueryExp;
86import javax.management.ReflectionException;
87import javax.management.RuntimeErrorException;
88import javax.management.RuntimeMBeanException;
89import javax.management.RuntimeOperationsException;
90import javax.management.loading.ClassLoaderRepository;
91
92/**
93 * This is the default class for MBean manipulation on the agent side. It
94 * contains the methods necessary for the creation, registration, and
95 * deletion of MBeans as well as the access methods for registered MBeans.
96 * This is the core component of the JMX infrastructure.
97 * <P>
98 * Every MBean which is added to the MBean server becomes manageable: its attributes and operations
99 * become remotely accessible through the connectors/adaptors connected to that MBean server.
100 * A Java object cannot be registered in the MBean server unless it is a JMX compliant MBean.
101 * <P>
102 * When an MBean is registered or unregistered in the MBean server an
103 * {@link javax.management.MBeanServerNotification MBeanServerNotification}
104 * Notification is emitted. To register an object as listener to MBeanServerNotifications
105 * you should call the MBean server method {@link #addNotificationListener addNotificationListener} with <CODE>ObjectName</CODE>
106 * the <CODE>ObjectName</CODE> of the {@link javax.management.MBeanServerDelegate MBeanServerDelegate}.
107 * This <CODE>ObjectName</CODE> is:
108 * <BR>
109 * <CODE>JMImplementation:type=MBeanServerDelegate</CODE>.
110 *
111 * @since 1.5
112 */
113public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
114
115 /** The MBeanInstantiator object used by the
116 * DefaultMBeanServerInterceptor */
117 private final transient MBeanInstantiator instantiator;
118
119 /** The MBean server object that is associated to the
120 * DefaultMBeanServerInterceptor */
121 private transient MBeanServer server = null;
122
123 /** The MBean server delegate object that is associated to the
124 * DefaultMBeanServerInterceptor */
125 private final transient MBeanServerDelegate delegate;
126
127 /** The Repository object used by the DefaultMBeanServerInterceptor */
128 private final transient Repository repository;
129
130 /** Wrappers for client listeners. */
131 /* See the comment before addNotificationListener below. */
132 private final transient
133 WeakHashMap<ListenerWrapper, WeakReference<ListenerWrapper>>
134 listenerWrappers =
135 new WeakHashMap<ListenerWrapper,
136 WeakReference<ListenerWrapper>>();
137
138 /** The default domain of the object names */
139 private final String domain;
140
141 /** The sequence number identifying the notifications sent */
142 // Now sequence number is handled by MBeanServerDelegate.
143 // private int sequenceNumber=0;
144
145 /**
146 * Creates a DefaultMBeanServerInterceptor with the specified
147 * repository instance.
148 * <p>Do not forget to call <code>initialize(outer,delegate)</code>
149 * before using this object.
150 * @param outer A pointer to the MBeanServer object that must be
151 * passed to the MBeans when invoking their
152 * {@link javax.management.MBeanRegistration} interface.
153 * @param delegate A pointer to the MBeanServerDelegate associated
154 * with the new MBeanServer. The new MBeanServer must register
155 * this MBean in its MBean repository.
156 * @param instantiator The MBeanInstantiator that will be used to
157 * instantiate MBeans and take care of class loading issues.
158 * @param repository The repository to use for this MBeanServer.
159 */
160 public DefaultMBeanServerInterceptor(MBeanServer outer,
161 MBeanServerDelegate delegate,
162 MBeanInstantiator instantiator,
163 Repository repository) {
164 if (outer == null) throw new
165 IllegalArgumentException("outer MBeanServer cannot be null");
166 if (delegate == null) throw new
167 IllegalArgumentException("MBeanServerDelegate cannot be null");
168 if (instantiator == null) throw new
169 IllegalArgumentException("MBeanInstantiator cannot be null");
170 if (repository == null) throw new
171 IllegalArgumentException("Repository cannot be null");
172
173 this.server = outer;
174 this.delegate = delegate;
175 this.instantiator = instantiator;
176 this.repository = repository;
177 this.domain = repository.getDefaultDomain();
178 }
179
180 public ObjectInstance createMBean(String className, ObjectName name)
181 throws ReflectionException, InstanceAlreadyExistsException,
182 MBeanRegistrationException, MBeanException,
183 NotCompliantMBeanException {
184
185 return createMBean(className, name, (Object[]) null, (String[]) null);
186
187 }
188
189 public ObjectInstance createMBean(String className, ObjectName name,
190 ObjectName loaderName)
191 throws ReflectionException, InstanceAlreadyExistsException,
192 MBeanRegistrationException, MBeanException,
193 NotCompliantMBeanException, InstanceNotFoundException {
194
195 return createMBean(className, name, loaderName, (Object[]) null,
196 (String[]) null);
197 }
198
199 public ObjectInstance createMBean(String className, ObjectName name,
200 Object[] params, String[] signature)
201 throws ReflectionException, InstanceAlreadyExistsException,
202 MBeanRegistrationException, MBeanException,
203 NotCompliantMBeanException {
204
205 try {
206 return createMBean(className, name, null, true,
207 params, signature);
208 } catch (InstanceNotFoundException e) {
209 /* Can only happen if loaderName doesn't exist, but we just
210 passed null, so we shouldn't get this exception. */
211 throw EnvHelp.initCause(
212 new IllegalArgumentException("Unexpected exception: " + e), e);
213 }
214 }
215
216 public ObjectInstance createMBean(String className, ObjectName name,
217 ObjectName loaderName,
218 Object[] params, String[] signature)
219 throws ReflectionException, InstanceAlreadyExistsException,
220 MBeanRegistrationException, MBeanException,
221 NotCompliantMBeanException, InstanceNotFoundException {
222
223 return createMBean(className, name, loaderName, false,
224 params, signature);
225 }
226
227 private ObjectInstance createMBean(String className, ObjectName name,
228 ObjectName loaderName,
229 boolean withDefaultLoaderRepository,
230 Object[] params, String[] signature)
231 throws ReflectionException, InstanceAlreadyExistsException,
232 MBeanRegistrationException, MBeanException,
233 NotCompliantMBeanException, InstanceNotFoundException {
234
235 Class<?> theClass;
236
237 if (className == null) {
238 final RuntimeException wrapped =
239 new IllegalArgumentException("The class name cannot be null");
240 throw new RuntimeOperationsException(wrapped,
241 "Exception occurred during MBean creation");
242 }
243
244 if (name != null) {
245 if (name.isPattern()) {
246 final RuntimeException wrapped =
247 new IllegalArgumentException("Invalid name->" +
248 name.toString());
249 final String msg = "Exception occurred during MBean creation";
250 throw new RuntimeOperationsException(wrapped, msg);
251 }
252
253 name = nonDefaultDomain(name);
254 }
255
256 checkMBeanPermission(className, null, null, "instantiate");
257 checkMBeanPermission(className, null, name, "registerMBean");
258
259 /* Load the appropriate class. */
260 if (withDefaultLoaderRepository) {
261 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
262 MBEANSERVER_LOGGER.logp(Level.FINER,
263 DefaultMBeanServerInterceptor.class.getName(),
264 "createMBean",
265 "ClassName = " + className + ", ObjectName = " + name);
266 }
267 theClass =
268 instantiator.findClassWithDefaultLoaderRepository(className);
269 } else if (loaderName == null) {
270 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
271 MBEANSERVER_LOGGER.logp(Level.FINER,
272 DefaultMBeanServerInterceptor.class.getName(),
273 "createMBean", "ClassName = " + className +
274 ", ObjectName = " + name + ", Loader name = null");
275 }
276
277 theClass = instantiator.findClass(className,
278 server.getClass().getClassLoader());
279 } else {
280 loaderName = nonDefaultDomain(loaderName);
281
282 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
283 MBEANSERVER_LOGGER.logp(Level.FINER,
284 DefaultMBeanServerInterceptor.class.getName(),
285 "createMBean", "ClassName = " + className +
286 ", ObjectName = " + name +
287 ", Loader name = " + loaderName);
288 }
289
290 theClass = instantiator.findClass(className, loaderName);
291 }
292
293 checkMBeanTrustPermission(theClass);
294
295 // Check that the MBean can be instantiated by the MBeanServer.
296 Introspector.testCreation(theClass);
297
298 // Check the JMX MBean compliance of the class
299 Introspector.checkCompliance(theClass);
300
301 Object moi= instantiator.instantiate(theClass, params, signature,
302 server.getClass().getClassLoader());
303
304 final String infoClassName = getNewMBeanClassName(moi);
305
306 return registerObject(infoClassName, moi, name);
307 }
308
309 public ObjectInstance registerMBean(Object object, ObjectName name)
310 throws InstanceAlreadyExistsException, MBeanRegistrationException,
311 NotCompliantMBeanException {
312
313 // ------------------------------
314 // ------------------------------
315 Class<?> theClass = object.getClass();
316
317 Introspector.checkCompliance(theClass);
318
319 final String infoClassName = getNewMBeanClassName(object);
320
321 checkMBeanPermission(infoClassName, null, name, "registerMBean");
322 checkMBeanTrustPermission(theClass);
323
324 return registerObject(infoClassName, object, name);
325 }
326
327 private static String getNewMBeanClassName(Object mbeanToRegister)
328 throws NotCompliantMBeanException {
329 if (mbeanToRegister instanceof DynamicMBean) {
330 DynamicMBean mbean = (DynamicMBean) mbeanToRegister;
331 final String name;
332 try {
333 name = mbean.getMBeanInfo().getClassName();
334 } catch (Exception e) {
335 // Includes case where getMBeanInfo() returns null
336 NotCompliantMBeanException ncmbe =
337 new NotCompliantMBeanException("Bad getMBeanInfo()");
338 ncmbe.initCause(e);
339 throw ncmbe;
340 }
341 if (name == null) {
342 final String msg = "MBeanInfo has null class name";
343 throw new NotCompliantMBeanException(msg);
344 }
345 return name;
346 } else
347 return mbeanToRegister.getClass().getName();
348 }
349
350 private final Set<ObjectName> beingUnregistered =
351 new HashSet<ObjectName>();
352
353 public void unregisterMBean(ObjectName name)
354 throws InstanceNotFoundException, MBeanRegistrationException {
355
356 if (name == null) {
357 final RuntimeException wrapped =
358 new IllegalArgumentException("Object name cannot be null");
359 throw new RuntimeOperationsException(wrapped,
360 "Exception occurred trying to unregister the MBean");
361 }
362
363 name = nonDefaultDomain(name);
364
365 /* The semantics of preDeregister are tricky. If it throws an
366 exception, then the unregisterMBean fails. This allows an
367 MBean to refuse to be unregistered. If it returns
368 successfully, then the unregisterMBean can proceed. In
369 this case the preDeregister may have cleaned up some state,
370 and will not expect to be called a second time. So if two
371 threads try to unregister the same MBean at the same time
372 then one of them must wait for the other one to either (a)
373 call preDeregister and get an exception or (b) call
374 preDeregister successfully and unregister the MBean.
375 Suppose thread T1 is unregistering an MBean and thread T2
376 is trying to unregister the same MBean, so waiting for T1.
377 Then a deadlock is possible if the preDeregister for T1
378 ends up needing a lock held by T2. Given the semantics
379 just described, there does not seem to be any way to avoid
380 this. This will not happen to code where it is clear for
381 any given MBean what thread may unregister that MBean.
382
383 On the other hand we clearly do not want a thread that is
384 unregistering MBean A to have to wait for another thread
385 that is unregistering another MBean B (see bug 6318664). A
386 deadlock in this situation could reasonably be considered
387 gratuitous. So holding a global lock across the
388 preDeregister call would be bad.
389
390 So we have a set of ObjectNames that some thread is
391 currently unregistering. When a thread wants to unregister
392 a name, it must first check if the name is in the set, and
393 if so it must wait. When a thread successfully unregisters
394 a name it removes the name from the set and notifies any
395 waiting threads that the set has changed.
396
397 This implies that we must be very careful to ensure that
398 the name is removed from the set and waiters notified, no
399 matter what code path is taken. */
400
401 synchronized (beingUnregistered) {
402 while (beingUnregistered.contains(name)) {
403 try {
404 beingUnregistered.wait();
405 } catch (InterruptedException e) {
406 throw new MBeanRegistrationException(e, e.toString());
407 // pretend the exception came from preDeregister;
408 // in another execution sequence it could have
409 }
410 }
411 beingUnregistered.add(name);
412 }
413
414 try {
415 exclusiveUnregisterMBean(name);
416 } finally {
417 synchronized (beingUnregistered) {
418 beingUnregistered.remove(name);
419 beingUnregistered.notifyAll();
420 }
421 }
422 }
423
424 private void exclusiveUnregisterMBean(ObjectName name)
425 throws InstanceNotFoundException, MBeanRegistrationException {
426
427 DynamicMBean instance = getMBean(name);
428 // may throw InstanceNotFoundException
429
430 checkMBeanPermission(instance, null, name, "unregisterMBean");
431
432 if (instance instanceof MBeanRegistration)
433 preDeregisterInvoke((MBeanRegistration) instance);
434
435 final Object resource = getResource(instance);
436
437 // Unregisters the MBean from the repository.
438 // Returns the resource context that was used.
439 // The returned context does nothing for regular MBeans.
440 // For ClassLoader MBeans and JMXNamespace (and JMXDomain)
441 // MBeans - the context makes it possible to unregister these
442 // objects from the appropriate framework artifacts, such as
443 // the CLR or the dispatcher, from within the repository lock.
444 // In case of success, we also need to call context.done() at the
445 // end of this method.
446 //
447 final ResourceContext context =
448 unregisterFromRepository(resource, instance, name);
449
450 try {
451 if (instance instanceof MBeanRegistration)
452 postDeregisterInvoke(name,(MBeanRegistration) instance);
453 } finally {
454 context.done();
455 }
456 }
457
458 public ObjectInstance getObjectInstance(ObjectName name)
459 throws InstanceNotFoundException {
460
461 name = nonDefaultDomain(name);
462 DynamicMBean instance = getMBean(name);
463
464 checkMBeanPermission(instance, null, name, "getObjectInstance");
465
466 final String className = getClassName(instance);
467
468 return new ObjectInstance(name, className);
469 }
470
471 public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
472 SecurityManager sm = System.getSecurityManager();
473 if (sm != null) {
474 // Check if the caller has the right to invoke 'queryMBeans'
475 //
476 checkMBeanPermission((String) null, null, null, "queryMBeans");
477
478 // Perform query without "query".
479 //
480 Set<ObjectInstance> list = queryMBeansImpl(name, null);
481
482 // Check if the caller has the right to invoke 'queryMBeans'
483 // on each specific classname/objectname in the list.
484 //
485 Set<ObjectInstance> allowedList =
486 new HashSet<ObjectInstance>(list.size());
487 for (ObjectInstance oi : list) {
488 try {
489 checkMBeanPermission(oi.getClassName(), null,
490 oi.getObjectName(), "queryMBeans");
491 allowedList.add(oi);
492 } catch (SecurityException e) {
493 // OK: Do not add this ObjectInstance to the list
494 }
495 }
496
497 // Apply query to allowed MBeans only.
498 //
499 return filterListOfObjectInstances(allowedList, query);
500 } else {
501 // Perform query.
502 //
503 return queryMBeansImpl(name, query);
504 }
505 }
506
507 private Set<ObjectInstance> queryMBeansImpl(ObjectName name,
508 QueryExp query) {
509 // Query the MBeans on the repository
510 //
511 Set<NamedObject> list = repository.query(name, query);
512
513 return (objectInstancesFromFilteredNamedObjects(list, query));
514 }
515
516 public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
517 Set<ObjectName> queryList;
518 SecurityManager sm = System.getSecurityManager();
519 if (sm != null) {
520 // Check if the caller has the right to invoke 'queryNames'
521 //
522 checkMBeanPermission((String) null, null, null, "queryNames");
523
524 // Perform query without "query".
525 //
526 Set<ObjectInstance> list = queryMBeansImpl(name, null);
527
528 // Check if the caller has the right to invoke 'queryNames'
529 // on each specific classname/objectname in the list.
530 //
531 Set<ObjectInstance> allowedList =
532 new HashSet<ObjectInstance>(list.size());
533 for (ObjectInstance oi : list) {
534 try {
535 checkMBeanPermission(oi.getClassName(), null,
536 oi.getObjectName(), "queryNames");
537 allowedList.add(oi);
538 } catch (SecurityException e) {
539 // OK: Do not add this ObjectInstance to the list
540 }
541 }
542
543 // Apply query to allowed MBeans only.
544 //
545 Set<ObjectInstance> queryObjectInstanceList =
546 filterListOfObjectInstances(allowedList, query);
547 queryList = new HashSet<ObjectName>(queryObjectInstanceList.size());
548 for (ObjectInstance oi : queryObjectInstanceList) {
549 queryList.add(oi.getObjectName());
550 }
551 } else {
552 // Perform query.
553 //
554 queryList = queryNamesImpl(name, query);
555 }
556 return queryList;
557 }
558
559 private Set<ObjectName> queryNamesImpl(ObjectName name, QueryExp query) {
560 // Query the MBeans on the repository
561 //
562 Set<NamedObject> list = repository.query(name, query);
563
564 return (objectNamesFromFilteredNamedObjects(list, query));
565 }
566
567 public boolean isRegistered(ObjectName name) {
568 if (name == null) {
569 throw new RuntimeOperationsException(
570 new IllegalArgumentException("Object name cannot be null"),
571 "Object name cannot be null");
572 }
573
574 name = nonDefaultDomain(name);
575
576 /* No Permission check */
577 // isRegistered is always unchecked as per JMX spec.
578
579 return (repository.contains(name));
580 }
581
582 public String[] getDomains() {
583 SecurityManager sm = System.getSecurityManager();
584 if (sm != null) {
585 // Check if the caller has the right to invoke 'getDomains'
586 //
587 checkMBeanPermission((String) null, null, null, "getDomains");
588
589 // Return domains
590 //
591 String[] domains = repository.getDomains();
592
593 // Check if the caller has the right to invoke 'getDomains'
594 // on each specific domain in the list.
595 //
596 List<String> result = new ArrayList<String>(domains.length);
597 for (int i = 0; i < domains.length; i++) {
598 try {
599 ObjectName dom = Util.newObjectName(domains[i] + ":x=x");
600 checkMBeanPermission((String) null, null, dom, "getDomains");
601 result.add(domains[i]);
602 } catch (SecurityException e) {
603 // OK: Do not add this domain to the list
604 }
605 }
606
607 // Make an array from result.
608 //
609 return result.toArray(new String[result.size()]);
610 } else {
611 return repository.getDomains();
612 }
613 }
614
615 public Integer getMBeanCount() {
616 return (repository.getCount());
617 }
618
619 public Object getAttribute(ObjectName name, String attribute)
620 throws MBeanException, AttributeNotFoundException,
621 InstanceNotFoundException, ReflectionException {
622
623 if (name == null) {
624 throw new RuntimeOperationsException(new
625 IllegalArgumentException("Object name cannot be null"),
626 "Exception occurred trying to invoke the getter on the MBean");
627 }
628 if (attribute == null) {
629 throw new RuntimeOperationsException(new
630 IllegalArgumentException("Attribute cannot be null"),
631 "Exception occurred trying to invoke the getter on the MBean");
632 }
633
634 name = nonDefaultDomain(name);
635
636 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
637 MBEANSERVER_LOGGER.logp(Level.FINER,
638 DefaultMBeanServerInterceptor.class.getName(),
639 "getAttribute",
640 "Attribute = " + attribute + ", ObjectName = " + name);
641 }
642
643 final DynamicMBean instance = getMBean(name);
644 checkMBeanPermission(instance, attribute, name, "getAttribute");
645
646 try {
647 return instance.getAttribute(attribute);
648 } catch (AttributeNotFoundException e) {
649 throw e;
650 } catch (Throwable t) {
651 rethrowMaybeMBeanException(t);
652 throw new AssertionError(); // not reached
653 }
654 }
655
656 public AttributeList getAttributes(ObjectName name, String[] attributes)
657 throws InstanceNotFoundException, ReflectionException {
658
659 if (name == null) {
660 throw new RuntimeOperationsException(new
661 IllegalArgumentException("ObjectName name cannot be null"),
662 "Exception occurred trying to invoke the getter on the MBean");
663 }
664
665 if (attributes == null) {
666 throw new RuntimeOperationsException(new
667 IllegalArgumentException("Attributes cannot be null"),
668 "Exception occurred trying to invoke the getter on the MBean");
669 }
670
671 name = nonDefaultDomain(name);
672
673 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
674 MBEANSERVER_LOGGER.logp(Level.FINER,
675 DefaultMBeanServerInterceptor.class.getName(),
676 "getAttributes", "ObjectName = " + name);
677 }
678
679 final DynamicMBean instance = getMBean(name);
680 final String[] allowedAttributes;
681 final SecurityManager sm = System.getSecurityManager();
682 if (sm == null)
683 allowedAttributes = attributes;
684 else {
685 final String classname = getClassName(instance);
686
687 // Check if the caller has the right to invoke 'getAttribute'
688 //
689 checkMBeanPermission(classname, null, name, "getAttribute");
690
691 // Check if the caller has the right to invoke 'getAttribute'
692 // on each specific attribute
693 //
694 List<String> allowedList =
695 new ArrayList<String>(attributes.length);
696 for (String attr : attributes) {
697 try {
698 checkMBeanPermission(classname, attr, name, "getAttribute");
699 allowedList.add(attr);
700 } catch (SecurityException e) {
701 // OK: Do not add this attribute to the list
702 }
703 }
704 allowedAttributes =
705 allowedList.toArray(new String[allowedList.size()]);
706 }
707
708 try {
709 return instance.getAttributes(allowedAttributes);
710 } catch (Throwable t) {
711 rethrow(t);
712 throw new AssertionError();
713 }
714 }
715
716 public void setAttribute(ObjectName name, Attribute attribute)
717 throws InstanceNotFoundException, AttributeNotFoundException,
718 InvalidAttributeValueException, MBeanException,
719 ReflectionException {
720
721 if (name == null) {
722 throw new RuntimeOperationsException(new
723 IllegalArgumentException("ObjectName name cannot be null"),
724 "Exception occurred trying to invoke the setter on the MBean");
725 }
726
727 if (attribute == null) {
728 throw new RuntimeOperationsException(new
729 IllegalArgumentException("Attribute cannot be null"),
730 "Exception occurred trying to invoke the setter on the MBean");
731 }
732
733 name = nonDefaultDomain(name);
734
735 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
736 MBEANSERVER_LOGGER.logp(Level.FINER,
737 DefaultMBeanServerInterceptor.class.getName(),
738 "setAttribute", "ObjectName = " + name +
739 ", Attribute = " + attribute.getName());
740 }
741
742 DynamicMBean instance = getMBean(name);
743 checkMBeanPermission(instance, attribute.getName(), name, "setAttribute");
744
745 try {
746 instance.setAttribute(attribute);
747 } catch (AttributeNotFoundException e) {
748 throw e;
749 } catch (InvalidAttributeValueException e) {
750 throw e;
751 } catch (Throwable t) {
752 rethrowMaybeMBeanException(t);
753 throw new AssertionError();
754 }
755 }
756
757 public AttributeList setAttributes(ObjectName name,
758 AttributeList attributes)
759 throws InstanceNotFoundException, ReflectionException {
760
761 if (name == null) {
762 throw new RuntimeOperationsException(new
763 IllegalArgumentException("ObjectName name cannot be null"),
764 "Exception occurred trying to invoke the setter on the MBean");
765 }
766
767 if (attributes == null) {
768 throw new RuntimeOperationsException(new
769 IllegalArgumentException("AttributeList cannot be null"),
770 "Exception occurred trying to invoke the setter on the MBean");
771 }
772
773 name = nonDefaultDomain(name);
774
775 final DynamicMBean instance = getMBean(name);
776 final AttributeList allowedAttributes;
777 final SecurityManager sm = System.getSecurityManager();
778 if (sm == null)
779 allowedAttributes = attributes;
780 else {
781 String classname = getClassName(instance);
782
783 // Check if the caller has the right to invoke 'setAttribute'
784 //
785 checkMBeanPermission(classname, null, name, "setAttribute");
786
787 // Check if the caller has the right to invoke 'setAttribute'
788 // on each specific attribute
789 //
790 allowedAttributes = new AttributeList(attributes.size());
791 for (Attribute attribute : attributes.asList()) {
792 try {
793 checkMBeanPermission(classname, attribute.getName(),
794 name, "setAttribute");
795 allowedAttributes.add(attribute);
796 } catch (SecurityException e) {
797 // OK: Do not add this attribute to the list
798 }
799 }
800 }
801 try {
802 return instance.setAttributes(allowedAttributes);
803 } catch (Throwable t) {
804 rethrow(t);
805 throw new AssertionError();
806 }
807 }
808
809 public Object invoke(ObjectName name, String operationName,
810 Object params[], String signature[])
811 throws InstanceNotFoundException, MBeanException,
812 ReflectionException {
813
814 name = nonDefaultDomain(name);
815
816 DynamicMBean instance = getMBean(name);
817 checkMBeanPermission(instance, operationName, name, "invoke");
818 try {
819 return instance.invoke(operationName, params, signature);
820 } catch (Throwable t) {
821 rethrowMaybeMBeanException(t);
822 throw new AssertionError();
823 }
824 }
825
826 /* Centralize some of the tedious exception wrapping demanded by the JMX
827 spec. */
828 private static void rethrow(Throwable t)
829 throws ReflectionException {
830 try {
831 throw t;
832 } catch (ReflectionException e) {
833 throw e;
834 } catch (RuntimeOperationsException e) {
835 throw e;
836 } catch (RuntimeErrorException e) {
837 throw e;
838 } catch (RuntimeException e) {
839 throw new RuntimeMBeanException(e, e.toString());
840 } catch (Error e) {
841 throw new RuntimeErrorException(e, e.toString());
842 } catch (Throwable t2) {
843 // should not happen
844 throw new RuntimeException("Unexpected exception", t2);
845 }
846 }
847
848 private static void rethrowMaybeMBeanException(Throwable t)
849 throws ReflectionException, MBeanException {
850 if (t instanceof MBeanException)
851 throw (MBeanException) t;
852 rethrow(t);
853 }
854
855 /**
856 * Register <code>object</code> in the repository, with the
857 * given <code>name</code>.
858 * This method is called by the various createMBean() flavours
859 * and by registerMBean() after all MBean compliance tests
860 * have been performed.
861 * <p>
862 * This method does not performed any kind of test compliance,
863 * and the caller should make sure that the given <code>object</code>
864 * is MBean compliant.
865 * <p>
866 * This methods performed all the basic steps needed for object
867 * registration:
868 * <ul>
869 * <li>If the <code>object</code> implements the MBeanRegistration
870 * interface, it invokes preRegister() on the object.</li>
871 * <li>Then the object is added to the repository with the given
872 * <code>name</code>.</li>
873 * <li>Finally, if the <code>object</code> implements the
874 * MBeanRegistration interface, it invokes postRegister()
875 * on the object.</li>
876 * </ul>
877 * @param object A reference to a MBean compliant object.
878 * @param name The ObjectName of the <code>object</code> MBean.
879 * @return the actual ObjectName with which the object was registered.
880 * @exception InstanceAlreadyExistsException if an object is already
881 * registered with that name.
882 * @exception MBeanRegistrationException if an exception occurs during
883 * registration.
884 **/
885 private ObjectInstance registerObject(String classname,
886 Object object, ObjectName name)
887 throws InstanceAlreadyExistsException,
888 MBeanRegistrationException,
889 NotCompliantMBeanException {
890
891 if (object == null) {
892 final RuntimeException wrapped =
893 new IllegalArgumentException("Cannot add null object");
894 throw new RuntimeOperationsException(wrapped,
895 "Exception occurred trying to register the MBean");
896 }
897
898 DynamicMBean mbean = Introspector.makeDynamicMBean(object);
899
900 return registerDynamicMBean(classname, mbean, name);
901 }
902
903 private ObjectInstance registerDynamicMBean(String classname,
904 DynamicMBean mbean,
905 ObjectName name)
906 throws InstanceAlreadyExistsException,
907 MBeanRegistrationException,
908 NotCompliantMBeanException {
909
910
911 name = nonDefaultDomain(name);
912
913 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
914 MBEANSERVER_LOGGER.logp(Level.FINER,
915 DefaultMBeanServerInterceptor.class.getName(),
916 "registerMBean", "ObjectName = " + name);
917 }
918
919 ObjectName logicalName = preRegister(mbean, server, name);
920
921 // preRegister returned successfully, so from this point on we
922 // must call postRegister(false) if there is any problem.
923 boolean registered = false;
924 boolean registerFailed = false;
925 ResourceContext context = null;
926
927 try {
928 if (mbean instanceof DynamicMBean2) {
929 try {
930 ((DynamicMBean2) mbean).preRegister2(server, logicalName);
931 registerFailed = true; // until we succeed
932 } catch (Exception e) {
933 if (e instanceof RuntimeException)
934 throw (RuntimeException) e;
935 if (e instanceof InstanceAlreadyExistsException)
936 throw (InstanceAlreadyExistsException) e;
937 throw new RuntimeException(e);
938 }
939 }
940
941 if (logicalName != name && logicalName != null) {
942 logicalName =
943 ObjectName.getInstance(nonDefaultDomain(logicalName));
944 }
945
946 checkMBeanPermission(classname, null, logicalName, "registerMBean");
947
948 if (logicalName == null) {
949 final RuntimeException wrapped =
950 new IllegalArgumentException("No object name specified");
951 throw new RuntimeOperationsException(wrapped,
952 "Exception occurred trying to register the MBean");
953 }
954
955 final Object resource = getResource(mbean);
956
957 // Register the MBean with the repository.
958 // Returns the resource context that was used.
959 // The returned context does nothing for regular MBeans.
960 // For ClassLoader MBeans the context makes it possible to register these
961 // objects with the appropriate framework artifacts, such as
962 // the CLR, from within the repository lock.
963 // In case of success, we also need to call context.done() at the
964 // end of this method.
965 //
966 context = registerWithRepository(resource, mbean, logicalName);
967
968
969 registerFailed = false;
970 registered = true;
971
972 } finally {
973 try {
974 postRegister(logicalName, mbean, registered, registerFailed);
975 } finally {
976 if (registered && context!=null) context.done();
977 }
978 }
979 return new ObjectInstance(logicalName, classname);
980 }
981
982 private static void throwMBeanRegistrationException(Throwable t, String where)
983 throws MBeanRegistrationException {
984 if (t instanceof RuntimeException) {
985 throw new RuntimeMBeanException((RuntimeException)t,
986 "RuntimeException thrown " + where);
987 } else if (t instanceof Error) {
988 throw new RuntimeErrorException((Error)t,
989 "Error thrown " + where);
990 } else if (t instanceof MBeanRegistrationException) {
991 throw (MBeanRegistrationException)t;
992 } else if (t instanceof Exception) {
993 throw new MBeanRegistrationException((Exception)t,
994 "Exception thrown " + where);
995 } else // neither Error nor Exception??
996 throw new RuntimeException(t);
997 }
998
999 private static ObjectName preRegister(
1000 DynamicMBean mbean, MBeanServer mbs, ObjectName name)
1001 throws InstanceAlreadyExistsException, MBeanRegistrationException {
1002
1003 ObjectName newName = null;
1004
1005 try {
1006 if (mbean instanceof MBeanRegistration)
1007 newName = ((MBeanRegistration) mbean).preRegister(mbs, name);
1008 } catch (Throwable t) {
1009 throwMBeanRegistrationException(t, "in preRegister method");
1010 }
1011
1012 if (newName != null) return newName;
1013 else return name;
1014 }
1015
1016 private static void postRegister(
1017 ObjectName logicalName, DynamicMBean mbean,
1018 boolean registrationDone, boolean registerFailed) {
1019
1020 if (registerFailed && mbean instanceof DynamicMBean2)
1021 ((DynamicMBean2) mbean).registerFailed();
1022 try {
1023 if (mbean instanceof MBeanRegistration)
1024 ((MBeanRegistration) mbean).postRegister(registrationDone);
1025 } catch (RuntimeException e) {
1026 MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
1027 "]: " + "Exception thrown by postRegister: " +
1028 "rethrowing <"+e+">, but keeping the MBean registered");
1029 throw new RuntimeMBeanException(e,
1030 "RuntimeException thrown in postRegister method: "+
1031 "rethrowing <"+e+">, but keeping the MBean registered");
1032 } catch (Error er) {
1033 MBEANSERVER_LOGGER.fine("While registering MBean ["+logicalName+
1034 "]: " + "Error thrown by postRegister: " +
1035 "rethrowing <"+er+">, but keeping the MBean registered");
1036 throw new RuntimeErrorException(er,
1037 "Error thrown in postRegister method: "+
1038 "rethrowing <"+er+">, but keeping the MBean registered");
1039 }
1040 }
1041
1042 private static void preDeregisterInvoke(MBeanRegistration moi)
1043 throws MBeanRegistrationException {
1044 try {
1045 moi.preDeregister();
1046 } catch (Throwable t) {
1047 throwMBeanRegistrationException(t, "in preDeregister method");
1048 }
1049 }
1050
1051 private static void postDeregisterInvoke(ObjectName mbean,
1052 MBeanRegistration moi) {
1053 try {
1054 moi.postDeregister();
1055 } catch (RuntimeException e) {
1056 MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
1057 "]: " + "Exception thrown by postDeregister: " +
1058 "rethrowing <"+e+">, although the MBean is succesfully " +
1059 "unregistered");
1060 throw new RuntimeMBeanException(e,
1061 "RuntimeException thrown in postDeregister method: "+
1062 "rethrowing <"+e+
1063 ">, although the MBean is sucessfully unregistered");
1064 } catch (Error er) {
1065 MBEANSERVER_LOGGER.fine("While unregistering MBean ["+mbean+
1066 "]: " + "Error thrown by postDeregister: " +
1067 "rethrowing <"+er+">, although the MBean is succesfully " +
1068 "unregistered");
1069 throw new RuntimeErrorException(er,
1070 "Error thrown in postDeregister method: "+
1071 "rethrowing <"+er+
1072 ">, although the MBean is sucessfully unregistered");
1073 }
1074 }
1075
1076 /**
1077 * Gets a specific MBean controlled by the DefaultMBeanServerInterceptor.
1078 * The name must have a non-default domain.
1079 */
1080 private DynamicMBean getMBean(ObjectName name)
1081 throws InstanceNotFoundException {
1082
1083 if (name == null) {
1084 throw new RuntimeOperationsException(new
1085 IllegalArgumentException("Object name cannot be null"),
1086 "Exception occurred trying to get an MBean");
1087 }
1088 DynamicMBean obj = repository.retrieve(name);
1089 if (obj == null) {
1090 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1091 MBEANSERVER_LOGGER.logp(Level.FINER,
1092 DefaultMBeanServerInterceptor.class.getName(),
1093 "getMBean", name + " : Found no object");
1094 }
1095 throw new InstanceNotFoundException(name.toString());
1096 }
1097 return obj;
1098 }
1099
1100 private static Object getResource(DynamicMBean mbean) {
1101 if (mbean instanceof DynamicMBean2)
1102 return ((DynamicMBean2) mbean).getResource();
1103 else
1104 return mbean;
1105 }
1106
1107 private ObjectName nonDefaultDomain(ObjectName name) {
1108 if (name == null || name.getDomain().length() > 0)
1109 return name;
1110
1111 /* The ObjectName looks like ":a=b", and that's what its
1112 toString() will return in this implementation. So
1113 we can just stick the default domain in front of it
1114 to get a non-default-domain name. We depend on the
1115 fact that toString() works like that and that it
1116 leaves wildcards in place (so we can detect an error
1117 if one is supplied where it shouldn't be). */
1118 final String completeName = domain + name;
1119
1120 return Util.newObjectName(completeName);
1121 }
1122
1123 public String getDefaultDomain() {
1124 return domain;
1125 }
1126
1127 /*
1128 * Notification handling.
1129 *
1130 * This is not trivial, because the MBeanServer translates the
1131 * source of a received notification from a reference to an MBean
1132 * into the ObjectName of that MBean. While that does make
1133 * notification sending easier for MBean writers, it comes at a
1134 * considerable cost. We need to replace the source of a
1135 * notification, which is basically wrong if there are also
1136 * listeners registered directly with the MBean (without going
1137 * through the MBean server). We also need to wrap the listener
1138 * supplied by the client of the MBeanServer with a listener that
1139 * performs the substitution before forwarding. This is why we
1140 * strongly discourage people from putting MBean references in the
1141 * source of their notifications. Instead they should arrange to
1142 * put the ObjectName there themselves.
1143 *
1144 * However, existing code relies on the substitution, so we are
1145 * stuck with it.
1146 *
1147 * Here's how we handle it. When you add a listener, we make a
1148 * ListenerWrapper around it. We look that up in the
1149 * listenerWrappers map, and if there was already a wrapper for
1150 * that listener with the given ObjectName, we reuse it. This map
1151 * is a WeakHashMap, so a listener that is no longer registered
1152 * with any MBean can be garbage collected.
1153 *
1154 * We cannot use simpler solutions such as always creating a new
1155 * wrapper or always registering the same listener with the MBean
1156 * and using the handback to find the client's original listener.
1157 * The reason is that we need to support the removeListener
1158 * variant that removes all (listener,filter,handback) triples on
1159 * a broadcaster that have a given listener. And we do not have
1160 * any way to inspect a broadcaster's internal list of triples.
1161 * So the same client listener must always map to the same
1162 * listener registered with the broadcaster.
1163 *
1164 * Another possible solution would be to map from ObjectName to
1165 * list of listener wrappers (or IdentityHashMap of listener
1166 * wrappers), making this list the first time a listener is added
1167 * on a given MBean, and removing it when the MBean is removed.
1168 * This is probably more costly in memory, but could be useful if
1169 * some day we don't want to rely on weak references.
1170 */
1171 public void addNotificationListener(ObjectName name,
1172 NotificationListener listener,
1173 NotificationFilter filter,
1174 Object handback)
1175 throws InstanceNotFoundException {
1176
1177 // ------------------------------
1178 // ------------------------------
1179 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1180 MBEANSERVER_LOGGER.logp(Level.FINER,
1181 DefaultMBeanServerInterceptor.class.getName(),
1182 "addNotificationListener", "ObjectName = " + name);
1183 }
1184
1185 DynamicMBean instance = getMBean(name);
1186 checkMBeanPermission(instance, null, name, "addNotificationListener");
1187
1188 NotificationBroadcaster broadcaster =
1189 getNotificationBroadcaster(name, instance,
1190 NotificationBroadcaster.class);
1191
1192 // ------------------
1193 // Check listener
1194 // ------------------
1195 if (listener == null) {
1196 throw new RuntimeOperationsException(new
1197 IllegalArgumentException("Null listener"),"Null listener");
1198 }
1199
1200 NotificationListener listenerWrapper =
1201 getListenerWrapper(listener, name, instance, true);
1202 broadcaster.addNotificationListener(listenerWrapper, filter, handback);
1203 }
1204
1205 public void addNotificationListener(ObjectName name,
1206 ObjectName listener,
1207 NotificationFilter filter,
1208 Object handback)
1209 throws InstanceNotFoundException {
1210
1211 // ------------------------------
1212 // ------------------------------
1213
1214 // ----------------
1215 // Get listener object
1216 // ----------------
1217 DynamicMBean instance = getMBean(listener);
1218 Object resource = getResource(instance);
1219 if (!(resource instanceof NotificationListener)) {
1220 throw new RuntimeOperationsException(new
1221 IllegalArgumentException(listener.getCanonicalName()),
1222 "The MBean " + listener.getCanonicalName() +
1223 "does not implement the NotificationListener interface") ;
1224 }
1225
1226 // ----------------
1227 // Add a listener on an MBean
1228 // ----------------
1229 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1230 MBEANSERVER_LOGGER.logp(Level.FINER,
1231 DefaultMBeanServerInterceptor.class.getName(),
1232 "addNotificationListener",
1233 "ObjectName = " + name + ", Listener = " + listener);
1234 }
1235 server.addNotificationListener(name,(NotificationListener) resource,
1236 filter, handback) ;
1237 }
1238
1239 public void removeNotificationListener(ObjectName name,
1240 NotificationListener listener)
1241 throws InstanceNotFoundException, ListenerNotFoundException {
1242 removeNotificationListener(name, listener, null, null, true);
1243 }
1244
1245 public void removeNotificationListener(ObjectName name,
1246 NotificationListener listener,
1247 NotificationFilter filter,
1248 Object handback)
1249 throws InstanceNotFoundException, ListenerNotFoundException {
1250 removeNotificationListener(name, listener, filter, handback, false);
1251 }
1252
1253 public void removeNotificationListener(ObjectName name,
1254 ObjectName listener)
1255 throws InstanceNotFoundException, ListenerNotFoundException {
1256 NotificationListener instance = getListener(listener);
1257
1258 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1259 MBEANSERVER_LOGGER.logp(Level.FINER,
1260 DefaultMBeanServerInterceptor.class.getName(),
1261 "removeNotificationListener",
1262 "ObjectName = " + name + ", Listener = " + listener);
1263 }
1264 server.removeNotificationListener(name, instance);
1265 }
1266
1267 public void removeNotificationListener(ObjectName name,
1268 ObjectName listener,
1269 NotificationFilter filter,
1270 Object handback)
1271 throws InstanceNotFoundException, ListenerNotFoundException {
1272
1273 NotificationListener instance = getListener(listener);
1274
1275 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1276 MBEANSERVER_LOGGER.logp(Level.FINER,
1277 DefaultMBeanServerInterceptor.class.getName(),
1278 "removeNotificationListener",
1279 "ObjectName = " + name + ", Listener = " + listener);
1280 }
1281 server.removeNotificationListener(name, instance, filter, handback);
1282 }
1283
1284 private NotificationListener getListener(ObjectName listener)
1285 throws ListenerNotFoundException {
1286 // ----------------
1287 // Get listener object
1288 // ----------------
1289 DynamicMBean instance;
1290 try {
1291 instance = getMBean(listener);
1292 } catch (InstanceNotFoundException e) {
1293 throw EnvHelp.initCause(
1294 new ListenerNotFoundException(e.getMessage()), e);
1295 }
1296
1297 Object resource = getResource(instance);
1298 if (!(resource instanceof NotificationListener)) {
1299 final RuntimeException exc =
1300 new IllegalArgumentException(listener.getCanonicalName());
1301 final String msg =
1302 "MBean " + listener.getCanonicalName() + " does not " +
1303 "implement " + NotificationListener.class.getName();
1304 throw new RuntimeOperationsException(exc, msg);
1305 }
1306 return (NotificationListener) resource;
1307 }
1308
1309 private void removeNotificationListener(ObjectName name,
1310 NotificationListener listener,
1311 NotificationFilter filter,
1312 Object handback,
1313 boolean removeAll)
1314 throws InstanceNotFoundException, ListenerNotFoundException {
1315
1316 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1317 MBEANSERVER_LOGGER.logp(Level.FINER,
1318 DefaultMBeanServerInterceptor.class.getName(),
1319 "removeNotificationListener", "ObjectName = " + name);
1320 }
1321
1322 DynamicMBean instance = getMBean(name);
1323 checkMBeanPermission(instance, null, name, "removeNotificationListener");
1324
1325 /* We could simplify the code by assigning broadcaster after
1326 assigning listenerWrapper, but that would change the error
1327 behavior when both the broadcaster and the listener are
1328 erroneous. */
1329
1330 Class<? extends NotificationBroadcaster> reqClass =
1331 removeAll ? NotificationBroadcaster.class : NotificationEmitter.class;
1332 NotificationBroadcaster broadcaster =
1333 getNotificationBroadcaster(name, instance, reqClass);
1334
1335 NotificationListener listenerWrapper =
1336 getListenerWrapper(listener, name, instance, false);
1337
1338 if (listenerWrapper == null)
1339 throw new ListenerNotFoundException("Unknown listener");
1340
1341 if (removeAll)
1342 broadcaster.removeNotificationListener(listenerWrapper);
1343 else {
1344 NotificationEmitter emitter = (NotificationEmitter) broadcaster;
1345 emitter.removeNotificationListener(listenerWrapper,
1346 filter,
1347 handback);
1348 }
1349 }
1350
1351 private static <T extends NotificationBroadcaster>
1352 T getNotificationBroadcaster(ObjectName name, Object instance,
1353 Class<T> reqClass) {
1354 if (reqClass.isInstance(instance))
1355 return reqClass.cast(instance);
1356 if (instance instanceof DynamicMBean2)
1357 instance = ((DynamicMBean2) instance).getResource();
1358 if (reqClass.isInstance(instance))
1359 return reqClass.cast(instance);
1360 final RuntimeException exc =
1361 new IllegalArgumentException(name.getCanonicalName());
1362 final String msg =
1363 "MBean " + name.getCanonicalName() + " does not " +
1364 "implement " + reqClass.getName();
1365 throw new RuntimeOperationsException(exc, msg);
1366 }
1367
1368 public MBeanInfo getMBeanInfo(ObjectName name)
1369 throws InstanceNotFoundException, IntrospectionException,
1370 ReflectionException {
1371
1372 // ------------------------------
1373 // ------------------------------
1374
1375 DynamicMBean moi = getMBean(name);
1376 final MBeanInfo mbi;
1377 try {
1378 mbi = moi.getMBeanInfo();
1379 } catch (RuntimeMBeanException e) {
1380 throw e;
1381 } catch (RuntimeErrorException e) {
1382 throw e;
1383 } catch (RuntimeException e) {
1384 throw new RuntimeMBeanException(e,
1385 "getMBeanInfo threw RuntimeException");
1386 } catch (Error e) {
1387 throw new RuntimeErrorException(e, "getMBeanInfo threw Error");
1388 }
1389 if (mbi == null)
1390 throw new JMRuntimeException("MBean " + name +
1391 "has no MBeanInfo");
1392
1393 checkMBeanPermission(mbi.getClassName(), null, name, "getMBeanInfo");
1394
1395 return mbi;
1396 }
1397
1398 public boolean isInstanceOf(ObjectName name, String className)
1399 throws InstanceNotFoundException {
1400
1401 final DynamicMBean instance = getMBean(name);
1402 checkMBeanPermission(instance, null, name, "isInstanceOf");
1403
1404 try {
1405 Object resource = getResource(instance);
1406
1407 final String resourceClassName =
1408 (resource instanceof DynamicMBean) ?
1409 getClassName((DynamicMBean) resource) :
1410 resource.getClass().getName();
1411
1412 if (resourceClassName.equals(className))
1413 return true;
1414 final ClassLoader cl = resource.getClass().getClassLoader();
1415
1416 final Class<?> classNameClass = Class.forName(className, false, cl);
1417 if (classNameClass.isInstance(resource))
1418 return true;
1419
1420 final Class<?> resourceClass = Class.forName(resourceClassName, false, cl);
1421 return classNameClass.isAssignableFrom(resourceClass);
1422 } catch (Exception x) {
1423 /* Could be SecurityException or ClassNotFoundException */
1424 if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
1425 MBEANSERVER_LOGGER.logp(Level.FINEST,
1426 DefaultMBeanServerInterceptor.class.getName(),
1427 "isInstanceOf", "Exception calling isInstanceOf", x);
1428 }
1429 return false;
1430 }
1431
1432 }
1433
1434 /**
1435 * <p>Return the {@link java.lang.ClassLoader} that was used for
1436 * loading the class of the named MBean.
1437 * @param mbeanName The ObjectName of the MBean.
1438 * @return The ClassLoader used for that MBean.
1439 * @exception InstanceNotFoundException if the named MBean is not found.
1440 */
1441 public ClassLoader getClassLoaderFor(ObjectName mbeanName)
1442 throws InstanceNotFoundException {
1443
1444 DynamicMBean instance = getMBean(mbeanName);
1445 checkMBeanPermission(instance, null, mbeanName, "getClassLoaderFor");
1446 return getResource(instance).getClass().getClassLoader();
1447 }
1448
1449 /**
1450 * <p>Return the named {@link java.lang.ClassLoader}.
1451 * @param loaderName The ObjectName of the ClassLoader.
1452 * @return The named ClassLoader.
1453 * @exception InstanceNotFoundException if the named ClassLoader
1454 * is not found.
1455 */
1456 public ClassLoader getClassLoader(ObjectName loaderName)
1457 throws InstanceNotFoundException {
1458
1459 if (loaderName == null) {
1460 checkMBeanPermission((String) null, null, null, "getClassLoader");
1461 return server.getClass().getClassLoader();
1462 }
1463
1464 DynamicMBean instance = getMBean(loaderName);
1465 checkMBeanPermission(instance, null, loaderName, "getClassLoader");
1466
1467 Object resource = getResource(instance);
1468
1469 /* Check if the given MBean is a ClassLoader */
1470 if (!(resource instanceof ClassLoader))
1471 throw new InstanceNotFoundException(loaderName.toString() +
1472 " is not a classloader");
1473
1474 return (ClassLoader) resource;
1475 }
1476
1477 /**
1478 * Sends an MBeanServerNotifications with the specified type for the
1479 * MBean with the specified ObjectName
1480 */
1481 private void sendNotification(String NotifType, ObjectName name) {
1482
1483 // ------------------------------
1484 // ------------------------------
1485
1486 // ---------------------
1487 // Create notification
1488 // ---------------------
1489 MBeanServerNotification notif = new MBeanServerNotification(
1490 NotifType,MBeanServerDelegate.DELEGATE_NAME,0,name);
1491
1492 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1493 MBEANSERVER_LOGGER.logp(Level.FINER,
1494 DefaultMBeanServerInterceptor.class.getName(),
1495 "sendNotification", NotifType + " " + name);
1496 }
1497
1498 delegate.sendNotification(notif);
1499 }
1500
1501 /**
1502 * Applies the specified queries to the set of NamedObjects.
1503 */
1504 private Set<ObjectName>
1505 objectNamesFromFilteredNamedObjects(Set<NamedObject> list,
1506 QueryExp query) {
1507 Set<ObjectName> result = new HashSet<ObjectName>();
1508 // No query ...
1509 if (query == null) {
1510 for (NamedObject no : list) {
1511 result.add(no.getName());
1512 }
1513 } else {
1514 // Access the filter
1515 final MBeanServer oldServer = QueryEval.getMBeanServer();
1516 query.setMBeanServer(server);
1517 try {
1518 for (NamedObject no : list) {
1519 boolean res;
1520 try {
1521 res = query.apply(no.getName());
1522 } catch (Exception e) {
1523 res = false;
1524 }
1525 if (res) {
1526 result.add(no.getName());
1527 }
1528 }
1529 } finally {
1530 /*
1531 * query.setMBeanServer is probably
1532 * QueryEval.setMBeanServer so put back the old
1533 * value. Since that method uses a ThreadLocal
1534 * variable, this code is only needed for the
1535 * unusual case where the user creates a custom
1536 * QueryExp that calls a nested query on another
1537 * MBeanServer.
1538 */
1539 query.setMBeanServer(oldServer);
1540 }
1541 }
1542 return result;
1543 }
1544
1545 /**
1546 * Applies the specified queries to the set of NamedObjects.
1547 */
1548 private Set<ObjectInstance>
1549 objectInstancesFromFilteredNamedObjects(Set<NamedObject> list,
1550 QueryExp query) {
1551 Set<ObjectInstance> result = new HashSet<ObjectInstance>();
1552 // No query ...
1553 if (query == null) {
1554 for (NamedObject no : list) {
1555 final DynamicMBean obj = no.getObject();
1556 final String className = safeGetClassName(obj);
1557 result.add(new ObjectInstance(no.getName(), className));
1558 }
1559 } else {
1560 // Access the filter
1561 MBeanServer oldServer = QueryEval.getMBeanServer();
1562 query.setMBeanServer(server);
1563 try {
1564 for (NamedObject no : list) {
1565 final DynamicMBean obj = no.getObject();
1566 boolean res;
1567 try {
1568 res = query.apply(no.getName());
1569 } catch (Exception e) {
1570 res = false;
1571 }
1572 if (res) {
1573 String className = safeGetClassName(obj);
1574 result.add(new ObjectInstance(no.getName(), className));
1575 }
1576 }
1577 } finally {
1578 /*
1579 * query.setMBeanServer is probably
1580 * QueryEval.setMBeanServer so put back the old
1581 * value. Since that method uses a ThreadLocal
1582 * variable, this code is only needed for the
1583 * unusual case where the user creates a custom
1584 * QueryExp that calls a nested query on another
1585 * MBeanServer.
1586 */
1587 query.setMBeanServer(oldServer);
1588 }
1589 }
1590 return result;
1591 }
1592
1593 private static String safeGetClassName(DynamicMBean mbean) {
1594 try {
1595 return getClassName(mbean);
1596 } catch (Exception e) {
1597 if (MBEANSERVER_LOGGER.isLoggable(Level.FINEST)) {
1598 MBEANSERVER_LOGGER.logp(Level.FINEST,
1599 DefaultMBeanServerInterceptor.class.getName(),
1600 "safeGetClassName",
1601 "Exception getting MBean class name", e);
1602 }
1603 return null;
1604 }
1605 }
1606
1607 /**
1608 * Applies the specified queries to the set of ObjectInstances.
1609 */
1610 private Set<ObjectInstance>
1611 filterListOfObjectInstances(Set<ObjectInstance> list,
1612 QueryExp query) {
1613 // Null query.
1614 //
1615 if (query == null) {
1616 return list;
1617 } else {
1618 Set<ObjectInstance> result = new HashSet<ObjectInstance>();
1619 // Access the filter.
1620 //
1621 for (ObjectInstance oi : list) {
1622 boolean res = false;
1623 MBeanServer oldServer = QueryEval.getMBeanServer();
1624 query.setMBeanServer(server);
1625 try {
1626 res = query.apply(oi.getObjectName());
1627 } catch (Exception e) {
1628 res = false;
1629 } finally {
1630 /*
1631 * query.setMBeanServer is probably
1632 * QueryEval.setMBeanServer so put back the old
1633 * value. Since that method uses a ThreadLocal
1634 * variable, this code is only needed for the
1635 * unusual case where the user creates a custom
1636 * QueryExp that calls a nested query on another
1637 * MBeanServer.
1638 */
1639 query.setMBeanServer(oldServer);
1640 }
1641 if (res) {
1642 result.add(oi);
1643 }
1644 }
1645 return result;
1646 }
1647 }
1648
1649 /*
1650 * Get the existing wrapper for this listener, name, and mbean, if
1651 * there is one. Otherwise, if "create" is true, create and
1652 * return one. Otherwise, return null.
1653 *
1654 * We use a WeakHashMap so that if the only reference to a user
1655 * listener is in listenerWrappers, it can be garbage collected.
1656 * This requires a certain amount of care, because only the key in
1657 * a WeakHashMap is weak; the value is strong. We need to recover
1658 * the existing wrapper object (not just an object that is equal
1659 * to it), so we would like listenerWrappers to map any
1660 * ListenerWrapper to the canonical ListenerWrapper for that
1661 * (listener,name,mbean) set. But we do not want this canonical
1662 * wrapper to be referenced strongly. Therefore we put it inside
1663 * a WeakReference and that is the value in the WeakHashMap.
1664 */
1665 private NotificationListener getListenerWrapper(NotificationListener l,
1666 ObjectName name,
1667 DynamicMBean mbean,
1668 boolean create) {
1669 Object resource = getResource(mbean);
1670 ListenerWrapper wrapper = new ListenerWrapper(l, name, resource);
1671 synchronized (listenerWrappers) {
1672 WeakReference<ListenerWrapper> ref = listenerWrappers.get(wrapper);
1673 if (ref != null) {
1674 NotificationListener existing = ref.get();
1675 if (existing != null)
1676 return existing;
1677 }
1678 if (create) {
1679 ref = new WeakReference<ListenerWrapper>(wrapper);
1680 listenerWrappers.put(wrapper, ref);
1681 return wrapper;
1682 } else
1683 return null;
1684 }
1685 }
1686
1687 public Object instantiate(String className) throws ReflectionException,
1688 MBeanException {
1689 throw new UnsupportedOperationException("Not supported yet.");
1690 }
1691
1692 public Object instantiate(String className, ObjectName loaderName) throws ReflectionException,
1693 MBeanException,
1694 InstanceNotFoundException {
1695 throw new UnsupportedOperationException("Not supported yet.");
1696 }
1697
1698 public Object instantiate(String className, Object[] params,
1699 String[] signature) throws ReflectionException, MBeanException {
1700 throw new UnsupportedOperationException("Not supported yet.");
1701 }
1702
1703 public Object instantiate(String className, ObjectName loaderName,
1704 Object[] params, String[] signature) throws ReflectionException,
1705 MBeanException,
1706 InstanceNotFoundException {
1707 throw new UnsupportedOperationException("Not supported yet.");
1708 }
1709
1710 public ObjectInputStream deserialize(ObjectName name, byte[] data) throws InstanceNotFoundException,
1711 OperationsException {
1712 throw new UnsupportedOperationException("Not supported yet.");
1713 }
1714
1715 public ObjectInputStream deserialize(String className, byte[] data) throws OperationsException,
1716 ReflectionException {
1717 throw new UnsupportedOperationException("Not supported yet.");
1718 }
1719
1720 public ObjectInputStream deserialize(String className, ObjectName loaderName,
1721 byte[] data) throws InstanceNotFoundException, OperationsException,
1722 ReflectionException {
1723 throw new UnsupportedOperationException("Not supported yet.");
1724 }
1725
1726 public ClassLoaderRepository getClassLoaderRepository() {
1727 throw new UnsupportedOperationException("Not supported yet.");
1728 }
1729
1730 private static class ListenerWrapper implements NotificationListener {
1731 ListenerWrapper(NotificationListener l, ObjectName name,
1732 Object mbean) {
1733 this.listener = l;
1734 this.name = name;
1735 this.mbean = mbean;
1736 }
1737
1738 public void handleNotification(Notification notification,
1739 Object handback) {
1740 if (notification != null) {
1741 if (notification.getSource() == mbean)
1742 notification.setSource(name);
1743 }
1744
1745 /*
1746 * Listeners are not supposed to throw exceptions. If
1747 * this one does, we could remove it from the MBean. It
1748 * might indicate that a connector has stopped working,
1749 * for instance, and there is no point in sending future
1750 * notifications over that connection. However, this
1751 * seems rather drastic, so instead we propagate the
1752 * exception and let the broadcaster handle it.
1753 */
1754 listener.handleNotification(notification, handback);
1755 }
1756
1757 @Override
1758 public boolean equals(Object o) {
1759 if (!(o instanceof ListenerWrapper))
1760 return false;
1761 ListenerWrapper w = (ListenerWrapper) o;
1762 return (w.listener == listener && w.mbean == mbean
1763 && w.name.equals(name));
1764 /*
1765 * We compare all three, in case the same MBean object
1766 * gets unregistered and then reregistered under a
1767 * different name, or the same name gets assigned to two
1768 * different MBean objects at different times. We do the
1769 * comparisons in this order to avoid the slow
1770 * ObjectName.equals when possible.
1771 */
1772 }
1773
1774 @Override
1775 public int hashCode() {
1776 return (System.identityHashCode(listener) ^
1777 System.identityHashCode(mbean));
1778 /*
1779 * We do not include name.hashCode() in the hash because
1780 * computing it is slow and usually we will not have two
1781 * instances of ListenerWrapper with the same mbean but
1782 * different ObjectNames. That can happen if the MBean is
1783 * unregistered from one name and reregistered with
1784 * another, and there is no garbage collection between; or
1785 * if the same object is registered under two names (which
1786 * is not recommended because MBeanRegistration will
1787 * break). But even in these unusual cases the hash code
1788 * does not have to be unique.
1789 */
1790 }
1791
1792 private NotificationListener listener;
1793 private ObjectName name;
1794 private Object mbean;
1795 }
1796
1797 // SECURITY CHECKS
1798 //----------------
1799
1800 private static String getClassName(DynamicMBean mbean) {
1801 if (mbean instanceof DynamicMBean2)
1802 return ((DynamicMBean2) mbean).getClassName();
1803 else
1804 return mbean.getMBeanInfo().getClassName();
1805 }
1806
1807 private static void checkMBeanPermission(DynamicMBean mbean,
1808 String member,
1809 ObjectName objectName,
1810 String actions) {
1811 SecurityManager sm = System.getSecurityManager();
1812 if (sm != null) {
1813 checkMBeanPermission(safeGetClassName(mbean),
1814 member,
1815 objectName,
1816 actions);
1817 }
1818 }
1819
1820 private static void checkMBeanPermission(String classname,
1821 String member,
1822 ObjectName objectName,
1823 String actions) {
1824 SecurityManager sm = System.getSecurityManager();
1825 if (sm != null) {
1826 Permission perm = new MBeanPermission(classname,
1827 member,
1828 objectName,
1829 actions);
1830 sm.checkPermission(perm);
1831 }
1832 }
1833
1834 private static void checkMBeanTrustPermission(final Class<?> theClass)
1835 throws SecurityException {
1836 SecurityManager sm = System.getSecurityManager();
1837 if (sm != null) {
1838 Permission perm = new MBeanTrustPermission("register");
1839 PrivilegedAction<ProtectionDomain> act =
1840 new PrivilegedAction<ProtectionDomain>() {
1841 public ProtectionDomain run() {
1842 return theClass.getProtectionDomain();
1843 }
1844 };
1845 ProtectionDomain pd = AccessController.doPrivileged(act);
1846 AccessControlContext acc =
1847 new AccessControlContext(new ProtectionDomain[] { pd });
1848 sm.checkPermission(perm, acc);
1849 }
1850 }
1851
1852 // ------------------------------------------------------------------
1853 //
1854 // Dealing with registration of special MBeans in the repository.
1855 //
1856 // ------------------------------------------------------------------
1857
1858 /**
1859 * A RegistrationContext that makes it possible to perform additional
1860 * post registration actions (or post unregistration actions) outside
1861 * of the repository lock, once postRegister (or postDeregister) has
1862 * been called.
1863 * The method {@code done()} will be called in registerMBean or
1864 * unregisterMBean, at the end.
1865 */
1866 private static interface ResourceContext extends RegistrationContext {
1867 public void done();
1868 /** An empty ResourceContext which does nothing **/
1869 public static final ResourceContext NONE = new ResourceContext() {
1870 public void done() {}
1871 public void registering() {}
1872 public void unregistered() {}
1873 };
1874 }
1875
1876 /**
1877 * Adds a MBean in the repository,
1878 * sends MBeanServerNotification.REGISTRATION_NOTIFICATION,
1879 * returns ResourceContext for special resources such as ClassLoaders
1880 * or JMXNamespaces. For regular MBean this method returns
1881 * ResourceContext.NONE.
1882 * @return a ResourceContext for special resources such as ClassLoaders
1883 * or JMXNamespaces.
1884 */
1885 private ResourceContext registerWithRepository(
1886 final Object resource,
1887 final DynamicMBean object,
1888 final ObjectName logicalName)
1889 throws InstanceAlreadyExistsException,
1890 MBeanRegistrationException {
1891
1892 // Creates a registration context, if needed.
1893 //
1894 final ResourceContext context =
1895 makeResourceContextFor(resource, logicalName);
1896
1897
1898 repository.addMBean(object, logicalName, context);
1899 // May throw InstanceAlreadyExistsException
1900
1901 // ---------------------
1902 // Send create event
1903 // ---------------------
1904 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1905 MBEANSERVER_LOGGER.logp(Level.FINER,
1906 DefaultMBeanServerInterceptor.class.getName(),
1907 "addObject", "Send create notification of object " +
1908 logicalName.getCanonicalName());
1909 }
1910
1911 sendNotification(
1912 MBeanServerNotification.REGISTRATION_NOTIFICATION,
1913 logicalName);
1914
1915 return context;
1916 }
1917
1918 /**
1919 * Removes a MBean in the repository,
1920 * sends MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
1921 * returns ResourceContext for special resources such as ClassLoaders
1922 * or JMXNamespaces, or null. For regular MBean this method returns
1923 * ResourceContext.NONE.
1924 *
1925 * @return a ResourceContext for special resources such as ClassLoaders
1926 * or JMXNamespaces.
1927 */
1928 private ResourceContext unregisterFromRepository(
1929 final Object resource,
1930 final DynamicMBean object,
1931 final ObjectName logicalName)
1932 throws InstanceNotFoundException {
1933
1934 // Creates a registration context, if needed.
1935 //
1936 final ResourceContext context =
1937 makeResourceContextFor(resource, logicalName);
1938
1939
1940 repository.remove(logicalName, context);
1941
1942 // ---------------------
1943 // Send deletion event
1944 // ---------------------
1945 if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
1946 MBEANSERVER_LOGGER.logp(Level.FINER,
1947 DefaultMBeanServerInterceptor.class.getName(),
1948 "unregisterMBean", "Send delete notification of object " +
1949 logicalName.getCanonicalName());
1950 }
1951
1952 sendNotification(MBeanServerNotification.UNREGISTRATION_NOTIFICATION,
1953 logicalName);
1954 return context;
1955 }
1956
1957
1958 /**
1959 * Registers a ClassLoader with the CLR.
1960 * This method is called by the ResourceContext from within the
1961 * repository lock.
1962 * @param loader The ClassLoader.
1963 * @param logicalName The ClassLoader MBean ObjectName.
1964 */
1965 private void addClassLoader(ClassLoader loader,
1966 final ObjectName logicalName) {
1967 /**
1968 * Called when the newly registered MBean is a ClassLoader
1969 * If so, tell the ClassLoaderRepository (CLR) about it. We do
1970 * this even if the loader is a PrivateClassLoader. In that
1971 * case, the CLR remembers the loader for use when it is
1972 * explicitly named (e.g. as the loader in createMBean) but
1973 * does not add it to the list that is consulted by
1974 * ClassLoaderRepository.loadClass.
1975 */
1976 final ModifiableClassLoaderRepository clr =
1977 instantiator.getClassLoaderRepository();
1978 if (clr == null) {
1979 final RuntimeException wrapped =
1980 new IllegalArgumentException(
1981 "Dynamic addition of class loaders" +
1982 " is not supported");
1983 throw new RuntimeOperationsException(wrapped,
1984 "Exception occurred trying to register" +
1985 " the MBean as a class loader");
1986 }
1987 clr.addClassLoader(logicalName, loader);
1988 }
1989
1990 /**
1991 * Unregisters a ClassLoader from the CLR.
1992 * This method is called by the ResourceContext from within the
1993 * repository lock.
1994 * @param loader The ClassLoader.
1995 * @param logicalName The ClassLoader MBean ObjectName.
1996 */
1997 private void removeClassLoader(ClassLoader loader,
1998 final ObjectName logicalName) {
1999 /**
2000 * Removes the MBean from the default loader repository.
2001 */
2002 if (loader != server.getClass().getClassLoader()) {
2003 final ModifiableClassLoaderRepository clr =
2004 instantiator.getClassLoaderRepository();
2005 if (clr != null) {
2006 clr.removeClassLoader(logicalName);
2007 }
2008 }
2009 }
2010
2011
2012 /**
2013 * Creates a ResourceContext for a ClassLoader MBean.
2014 * The resource context makes it possible to add the ClassLoader to
2015 * (ResourceContext.registering) or resp. remove the ClassLoader from
2016 * (ResourceContext.unregistered) the CLR
2017 * when the associated MBean is added to or resp. removed from the
2018 * repository.
2019 *
2020 * @param loader The ClassLoader MBean being registered or
2021 * unregistered.
2022 * @param logicalName The name of the ClassLoader MBean.
2023 * @return a ResourceContext that takes in charge the addition or removal
2024 * of the loader to or from the CLR.
2025 */
2026 private ResourceContext createClassLoaderContext(
2027 final ClassLoader loader,
2028 final ObjectName logicalName) {
2029 return new ResourceContext() {
2030
2031 public void registering() {
2032 addClassLoader(loader, logicalName);
2033 }
2034
2035 public void unregistered() {
2036 removeClassLoader(loader, logicalName);
2037 }
2038
2039 public void done() {
2040 }
2041 };
2042 }
2043
2044 /**
2045 * Creates a ResourceContext for the given resource.
2046 * If the resource does not need a ResourceContext, returns
2047 * ResourceContext.NONE.
2048 * At this time, only ClassLoaders need a ResourceContext.
2049 *
2050 * @param resource The resource being registered or unregistered.
2051 * @param logicalName The name of the associated MBean.
2052 * @return
2053 */
2054 private ResourceContext makeResourceContextFor(Object resource,
2055 ObjectName logicalName) {
2056 if (resource instanceof ClassLoader) {
2057 return createClassLoaderContext((ClassLoader) resource,
2058 logicalName);
2059 }
2060 return ResourceContext.NONE;
2061 }
2062
2063
2064}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t