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+
26+package com.sun.jmx.interceptor;
27+
28+
29+// JMX RI
30+import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
31+import com.sun.jmx.mbeanserver.DynamicMBean2;
32+import com.sun.jmx.mbeanserver.Introspector;
33+import com.sun.jmx.mbeanserver.MBeanInstantiator;
34+import com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository;
35+import com.sun.jmx.mbeanserver.NamedObject;
36+import com.sun.jmx.mbeanserver.Repository;
37+import com.sun.jmx.mbeanserver.Repository.RegistrationContext;
38+import com.sun.jmx.mbeanserver.Util;
39+import com.sun.jmx.remote.util.EnvHelp;
40+
41+import java.io.ObjectInputStream;
42+import java.lang.ref.WeakReference;
43+import java.security.AccessControlContext;
44+import java.security.AccessController;
45+import java.security.Permission;
46+import java.security.PrivilegedAction;
47+import java.security.ProtectionDomain;
48+import java.util.ArrayList;
49+import java.util.HashSet;
50+import java.util.List;
51+import java.util.Set;
52+import java.util.WeakHashMap;
53+import java.util.logging.Level;
54+
55+// JMX import
56+import javax.management.Attribute;
57+import javax.management.AttributeList;
58+import javax.management.AttributeNotFoundException;
59+import javax.management.DynamicMBean;
60+import javax.management.InstanceAlreadyExistsException;
61+import javax.management.InstanceNotFoundException;
62+import javax.management.IntrospectionException;
63+import javax.management.InvalidAttributeValueException;
64+import javax.management.JMRuntimeException;
65+import javax.management.ListenerNotFoundException;
66+import javax.management.MBeanException;
67+import javax.management.MBeanInfo;
68+import javax.management.MBeanPermission;
69+import javax.management.MBeanRegistration;
70+import javax.management.MBeanRegistrationException;
71+import javax.management.MBeanServer;
72+import javax.management.MBeanServerDelegate;
73+import javax.management.MBeanServerNotification;
74+import javax.management.MBeanTrustPermission;
75+import javax.management.NotCompliantMBeanException;
76+import javax.management.Notification;
77+import javax.management.NotificationBroadcaster;
78+import javax.management.NotificationEmitter;
79+import javax.management.NotificationFilter;
80+import javax.management.NotificationListener;
81+import javax.management.ObjectInstance;
82+import javax.management.ObjectName;
83+import javax.management.OperationsException;
84+import javax.management.QueryEval;
85+import javax.management.QueryExp;
86+import javax.management.ReflectionException;
87+import javax.management.RuntimeErrorException;
88+import javax.management.RuntimeMBeanException;
89+import javax.management.RuntimeOperationsException;
90+import 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+ */
113+public 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