2
|
1 |
/*
|
715
|
2 |
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
|
2
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation. Sun designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Sun in the LICENSE file that accompanied this code.
|
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
|
21 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
22 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
23 |
* have any questions.
|
|
24 |
*/
|
|
25 |
|
|
26 |
package com.sun.jmx.mbeanserver;
|
|
27 |
|
|
28 |
import static com.sun.jmx.mbeanserver.Util.*;
|
|
29 |
|
|
30 |
import java.util.Iterator;
|
|
31 |
import java.util.Set;
|
|
32 |
|
|
33 |
import javax.management.InstanceAlreadyExistsException;
|
|
34 |
import javax.management.JMX;
|
|
35 |
import javax.management.MBeanServer;
|
|
36 |
import javax.management.NotCompliantMBeanException;
|
|
37 |
import javax.management.ObjectName;
|
687
|
38 |
import javax.management.openmbean.MXBeanMappingFactory;
|
|
39 |
import javax.management.openmbean.MXBeanMappingFactoryClass;
|
2
|
40 |
|
|
41 |
/**
|
|
42 |
* Base class for MXBeans.
|
|
43 |
*
|
|
44 |
* @since 1.6
|
|
45 |
*/
|
|
46 |
public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
|
|
47 |
|
|
48 |
/**
|
|
49 |
<p>Construct an MXBean that wraps the given resource using the
|
|
50 |
given MXBean interface.</p>
|
|
51 |
|
|
52 |
@param resource the underlying resource for the new MXBean.
|
|
53 |
|
|
54 |
@param mxbeanInterface the interface to be used to determine
|
|
55 |
the MXBean's management interface.
|
|
56 |
|
|
57 |
@param <T> a type parameter that allows the compiler to check
|
|
58 |
that {@code resource} implements {@code mxbeanInterface},
|
|
59 |
provided that {@code mxbeanInterface} is a class constant like
|
|
60 |
{@code SomeMXBean.class}.
|
|
61 |
|
|
62 |
@throws IllegalArgumentException if {@code resource} is null or
|
|
63 |
if it does not implement the class {@code mxbeanInterface} or if
|
|
64 |
that class is not a valid MXBean interface.
|
|
65 |
*/
|
687
|
66 |
public <T> MXBeanSupport(T resource, Class<T> mxbeanInterface,
|
|
67 |
MXBeanMappingFactory mappingFactory)
|
2
|
68 |
throws NotCompliantMBeanException {
|
687
|
69 |
super(resource, mxbeanInterface, mappingFactory);
|
2
|
70 |
}
|
|
71 |
|
|
72 |
@Override
|
687
|
73 |
MBeanIntrospector<ConvertingMethod>
|
|
74 |
getMBeanIntrospector(MXBeanMappingFactory mappingFactory) {
|
|
75 |
return MXBeanIntrospector.getInstance(mappingFactory);
|
2
|
76 |
}
|
|
77 |
|
|
78 |
@Override
|
|
79 |
Object getCookie() {
|
|
80 |
return mxbeanLookup;
|
|
81 |
}
|
|
82 |
|
687
|
83 |
static <T> Class<? super T> findMXBeanInterface(Class<T> resourceClass) {
|
2
|
84 |
if (resourceClass == null)
|
|
85 |
throw new IllegalArgumentException("Null resource class");
|
|
86 |
final Set<Class<?>> intfs = transitiveInterfaces(resourceClass);
|
|
87 |
final Set<Class<?>> candidates = newSet();
|
|
88 |
for (Class<?> intf : intfs) {
|
|
89 |
if (JMX.isMXBeanInterface(intf))
|
|
90 |
candidates.add(intf);
|
|
91 |
}
|
|
92 |
reduce:
|
|
93 |
while (candidates.size() > 1) {
|
|
94 |
for (Class<?> intf : candidates) {
|
|
95 |
for (Iterator<Class<?>> it = candidates.iterator(); it.hasNext();
|
|
96 |
) {
|
|
97 |
final Class<?> intf2 = it.next();
|
|
98 |
if (intf != intf2 && intf2.isAssignableFrom(intf)) {
|
|
99 |
it.remove();
|
|
100 |
continue reduce;
|
|
101 |
}
|
|
102 |
}
|
|
103 |
}
|
|
104 |
final String msg =
|
|
105 |
"Class " + resourceClass.getName() + " implements more than " +
|
|
106 |
"one MXBean interface: " + candidates;
|
|
107 |
throw new IllegalArgumentException(msg);
|
|
108 |
}
|
|
109 |
if (candidates.iterator().hasNext()) {
|
687
|
110 |
return Util.cast(candidates.iterator().next());
|
2
|
111 |
} else {
|
|
112 |
final String msg =
|
|
113 |
"Class " + resourceClass.getName() +
|
|
114 |
" is not a JMX compliant MXBean";
|
|
115 |
throw new IllegalArgumentException(msg);
|
|
116 |
}
|
|
117 |
}
|
|
118 |
|
|
119 |
/* Return all interfaces inherited by this class, directly or
|
|
120 |
* indirectly through the parent class and interfaces.
|
|
121 |
*/
|
687
|
122 |
private static Set<Class<?>> transitiveInterfaces(Class<?> c) {
|
2
|
123 |
Set<Class<?>> set = newSet();
|
|
124 |
transitiveInterfaces(c, set);
|
|
125 |
return set;
|
|
126 |
}
|
|
127 |
private static void transitiveInterfaces(Class<?> c, Set<Class<?>> intfs) {
|
|
128 |
if (c == null)
|
|
129 |
return;
|
|
130 |
if (c.isInterface())
|
|
131 |
intfs.add(c);
|
|
132 |
transitiveInterfaces(c.getSuperclass(), intfs);
|
687
|
133 |
for (Class<?> sup : c.getInterfaces())
|
2
|
134 |
transitiveInterfaces(sup, intfs);
|
|
135 |
}
|
|
136 |
|
|
137 |
/*
|
|
138 |
* The sequence of events for tracking inter-MXBean references is
|
|
139 |
* relatively complicated. We use the magical preRegister2 method
|
|
140 |
* which the MBeanServer knows about. The steps during registration
|
|
141 |
* are:
|
|
142 |
* (1) Call user preRegister, if any. If exception, abandon.
|
|
143 |
* (2) Call preRegister2 and hence this register method. If exception,
|
|
144 |
* call postRegister(false) and abandon.
|
|
145 |
* (3) Try to register the MBean. If exception, call registerFailed()
|
|
146 |
* which will call the unregister method. (Also call postRegister(false).)
|
|
147 |
* (4) If we get this far, we can call postRegister(true).
|
|
148 |
*
|
|
149 |
* When we are wrapped in an instance of javax.management.StandardMBean,
|
|
150 |
* things are simpler. That class calls this method from its preRegister,
|
|
151 |
* and propagates any exception. There is no user preRegister in this case.
|
|
152 |
* If this method succeeds but registration subsequently fails,
|
|
153 |
* StandardMBean calls unregister from its postRegister(false) method.
|
|
154 |
*/
|
|
155 |
@Override
|
|
156 |
public void register(MBeanServer server, ObjectName name)
|
|
157 |
throws InstanceAlreadyExistsException {
|
|
158 |
if (name == null)
|
|
159 |
throw new IllegalArgumentException("Null object name");
|
|
160 |
// eventually we could have some logic to supply a default name
|
|
161 |
|
|
162 |
synchronized (lock) {
|
687
|
163 |
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
|
2
|
164 |
this.mxbeanLookup.addReference(name, getResource());
|
|
165 |
this.objectName = name;
|
|
166 |
}
|
|
167 |
}
|
|
168 |
|
|
169 |
@Override
|
|
170 |
public void unregister() {
|
|
171 |
synchronized (lock) {
|
687
|
172 |
if (mxbeanLookup != null) {
|
|
173 |
if (mxbeanLookup.removeReference(objectName, getResource()))
|
|
174 |
objectName = null;
|
|
175 |
}
|
|
176 |
// XXX: need to revisit the whole register/unregister logic in
|
|
177 |
// the face of wrapping. The mxbeanLookup!=null test is a hack.
|
|
178 |
// If you wrap an MXBean in a MyWrapperMBean and register it,
|
|
179 |
// the lookup table should contain the wrapped object. But that
|
|
180 |
// implies that MyWrapperMBean calls register, which today it
|
|
181 |
// can't within the public API.
|
2
|
182 |
}
|
|
183 |
}
|
687
|
184 |
private final Object lock = new Object(); // for mxbeanLookup and objectName
|
2
|
185 |
|
687
|
186 |
private MXBeanLookup.Plain mxbeanLookup;
|
2
|
187 |
private ObjectName objectName;
|
|
188 |
}
|