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 javax.management.Attribute;
|
|
31 |
import javax.management.AttributeList;
|
|
32 |
import javax.management.AttributeNotFoundException;
|
|
33 |
import javax.management.InvalidAttributeValueException;
|
|
34 |
import javax.management.MBeanException;
|
|
35 |
import javax.management.MBeanInfo;
|
|
36 |
import javax.management.MBeanRegistration;
|
|
37 |
import javax.management.MBeanServer;
|
|
38 |
import javax.management.NotCompliantMBeanException;
|
|
39 |
import javax.management.ObjectName;
|
|
40 |
import javax.management.ReflectionException;
|
687
|
41 |
import javax.management.openmbean.MXBeanMappingFactory;
|
2
|
42 |
|
|
43 |
/**
|
|
44 |
* Base class for MBeans. There is one instance of this class for
|
|
45 |
* every Standard MBean and every MXBean. We try to limit the amount
|
|
46 |
* of information per instance so we can handle very large numbers of
|
|
47 |
* MBeans comfortably.
|
|
48 |
*
|
|
49 |
* @param <M> either Method or ConvertingMethod, for Standard MBeans
|
|
50 |
* and MXBeans respectively.
|
|
51 |
*
|
|
52 |
* @since 1.6
|
|
53 |
*/
|
|
54 |
/*
|
|
55 |
* We maintain a couple of caches to increase sharing between
|
|
56 |
* different MBeans of the same type and also to reduce creation time
|
|
57 |
* for the second and subsequent instances of the same type.
|
|
58 |
*
|
|
59 |
* The first cache maps from an MBean interface to a PerInterface
|
|
60 |
* object containing information parsed out of the interface. The
|
|
61 |
* interface is either a Standard MBean interface or an MXBean
|
|
62 |
* interface, and there is one cache for each case.
|
|
63 |
*
|
|
64 |
* The PerInterface includes an MBeanInfo. This contains the
|
|
65 |
* attributes and operations parsed out of the interface's methods,
|
|
66 |
* plus a basic Descriptor for the interface containing at least the
|
|
67 |
* interfaceClassName field and any fields derived from annotations on
|
|
68 |
* the interface. This MBeanInfo can never be the MBeanInfo for any
|
|
69 |
* actual MBean, because an MBeanInfo's getClassName() is the name of
|
|
70 |
* a concrete class and we don't know what the class will be.
|
|
71 |
* Furthermore a real MBeanInfo may need to add constructors and/or
|
|
72 |
* notifications to the MBeanInfo.
|
|
73 |
*
|
|
74 |
* The PerInterface also contains an MBeanDispatcher which is able to
|
|
75 |
* route getAttribute, setAttribute, and invoke to the appropriate
|
|
76 |
* method of the interface, including doing any necessary translation
|
|
77 |
* of parameters and return values for MXBeans.
|
|
78 |
*
|
|
79 |
* The PerInterface also contains the original Class for the interface.
|
|
80 |
*
|
|
81 |
* We need to be careful about references. When there are no MBeans
|
|
82 |
* with a given interface, there must not be any strong references to
|
|
83 |
* the interface Class. Otherwise it could never be garbage collected,
|
|
84 |
* and neither could its ClassLoader or any other classes loaded by
|
|
85 |
* its ClassLoader. Therefore the cache must wrap the PerInterface
|
|
86 |
* in a WeakReference. Each instance of MBeanSupport has a strong
|
|
87 |
* reference to its PerInterface, which prevents PerInterface instances
|
|
88 |
* from being garbage-collected prematurely.
|
|
89 |
*
|
|
90 |
* The second cache maps from a concrete class and an MBean interface
|
|
91 |
* that that class implements to the MBeanInfo for that class and
|
|
92 |
* interface. (The ability to specify an interface separately comes
|
|
93 |
* from the class StandardMBean. MBeans registered directly in the
|
|
94 |
* MBean Server will always have the same interface here.)
|
|
95 |
*
|
|
96 |
* The MBeanInfo in this second cache will be the MBeanInfo from the
|
|
97 |
* PerInterface cache for the given itnerface, but with the
|
|
98 |
* getClassName() having the concrete class's name, and the public
|
|
99 |
* constructors based on the concrete class's constructors. This
|
|
100 |
* MBeanInfo can be shared between all instances of the concrete class
|
|
101 |
* specifying the same interface, except instances that are
|
|
102 |
* NotificationBroadcasters. NotificationBroadcasters supply the
|
|
103 |
* MBeanNotificationInfo[] in the MBeanInfo based on the instance
|
|
104 |
* method NotificationBroadcaster.getNotificationInfo(), so two
|
|
105 |
* instances of the same concrete class do not necessarily have the
|
|
106 |
* same MBeanNotificationInfo[]. Currently we do not try to detect
|
|
107 |
* when they do, although it would probably be worthwhile doing that
|
|
108 |
* since it is a very common case.
|
|
109 |
*
|
|
110 |
* Standard MBeans additionally have the property that
|
|
111 |
* getNotificationInfo() must in principle be called every time
|
|
112 |
* getMBeanInfo() is called for the MBean, since the returned array is
|
|
113 |
* allowed to change over time. We attempt to reduce the cost of
|
|
114 |
* doing this by detecting when the Standard MBean is a subclass of
|
|
115 |
* NotificationBroadcasterSupport that does not override
|
|
116 |
* getNotificationInfo(), meaning that the MBeanNotificationInfo[] is
|
|
117 |
* the one that was supplied to the constructor. MXBeans do not have
|
|
118 |
* this problem because their getNotificationInfo() method is called
|
|
119 |
* only once.
|
|
120 |
*
|
|
121 |
*/
|
|
122 |
public abstract class MBeanSupport<M>
|
|
123 |
implements DynamicMBean2, MBeanRegistration {
|
|
124 |
|
687
|
125 |
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType,
|
|
126 |
MXBeanMappingFactory mappingFactory)
|
2
|
127 |
throws NotCompliantMBeanException {
|
687
|
128 |
if (mbeanInterfaceType == null)
|
2
|
129 |
throw new NotCompliantMBeanException("Null MBean interface");
|
687
|
130 |
if (!mbeanInterfaceType.isInstance(resource)) {
|
2
|
131 |
final String msg =
|
|
132 |
"Resource class " + resource.getClass().getName() +
|
687
|
133 |
" is not an instance of " + mbeanInterfaceType.getName();
|
2
|
134 |
throw new NotCompliantMBeanException(msg);
|
|
135 |
}
|
|
136 |
this.resource = resource;
|
687
|
137 |
MBeanIntrospector<M> introspector = getMBeanIntrospector(mappingFactory);
|
|
138 |
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
|
2
|
139 |
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
|
|
140 |
}
|
|
141 |
|
|
142 |
/** Return the appropriate introspector for this type of MBean. */
|
687
|
143 |
abstract MBeanIntrospector<M>
|
|
144 |
getMBeanIntrospector(MXBeanMappingFactory mappingFactory);
|
2
|
145 |
|
|
146 |
/**
|
|
147 |
* Return a cookie for this MBean. This cookie will be passed to
|
|
148 |
* MBean method invocations where it can supply additional information
|
|
149 |
* to the invocation. For example, with MXBeans it can be used to
|
|
150 |
* supply the MXBeanLookup context for resolving inter-MXBean references.
|
|
151 |
*/
|
|
152 |
abstract Object getCookie();
|
|
153 |
|
|
154 |
public final boolean isMXBean() {
|
|
155 |
return perInterface.isMXBean();
|
|
156 |
}
|
|
157 |
|
|
158 |
// Methods that javax.management.StandardMBean should call from its
|
|
159 |
// preRegister and postRegister, given that it is not supposed to
|
|
160 |
// call the contained object's preRegister etc methods even if it has them
|
|
161 |
public abstract void register(MBeanServer mbs, ObjectName name)
|
|
162 |
throws Exception;
|
|
163 |
public abstract void unregister();
|
|
164 |
|
|
165 |
public final ObjectName preRegister(MBeanServer server, ObjectName name)
|
|
166 |
throws Exception {
|
|
167 |
if (resource instanceof MBeanRegistration)
|
687
|
168 |
name = ((MBeanRegistration) resource).preRegister(server, name);
|
|
169 |
return name;
|
2
|
170 |
}
|
|
171 |
|
|
172 |
public final void preRegister2(MBeanServer server, ObjectName name)
|
|
173 |
throws Exception {
|
|
174 |
register(server, name);
|
|
175 |
}
|
|
176 |
|
|
177 |
public final void registerFailed() {
|
|
178 |
unregister();
|
|
179 |
}
|
|
180 |
|
|
181 |
public final void postRegister(Boolean registrationDone) {
|
|
182 |
if (resource instanceof MBeanRegistration)
|
|
183 |
((MBeanRegistration) resource).postRegister(registrationDone);
|
|
184 |
}
|
|
185 |
|
|
186 |
public final void preDeregister() throws Exception {
|
|
187 |
if (resource instanceof MBeanRegistration)
|
|
188 |
((MBeanRegistration) resource).preDeregister();
|
|
189 |
}
|
|
190 |
|
|
191 |
public final void postDeregister() {
|
|
192 |
// Undo any work from registration. We do this in postDeregister
|
|
193 |
// not preDeregister, because if the user preDeregister throws an
|
|
194 |
// exception then the MBean is not unregistered.
|
|
195 |
try {
|
|
196 |
unregister();
|
|
197 |
} finally {
|
|
198 |
if (resource instanceof MBeanRegistration)
|
|
199 |
((MBeanRegistration) resource).postDeregister();
|
|
200 |
}
|
|
201 |
}
|
|
202 |
|
|
203 |
public final Object getAttribute(String attribute)
|
|
204 |
throws AttributeNotFoundException,
|
|
205 |
MBeanException,
|
|
206 |
ReflectionException {
|
|
207 |
return perInterface.getAttribute(resource, attribute, getCookie());
|
|
208 |
}
|
|
209 |
|
|
210 |
public final AttributeList getAttributes(String[] attributes) {
|
|
211 |
final AttributeList result = new AttributeList(attributes.length);
|
|
212 |
for (String attrName : attributes) {
|
|
213 |
try {
|
|
214 |
final Object attrValue = getAttribute(attrName);
|
|
215 |
result.add(new Attribute(attrName, attrValue));
|
|
216 |
} catch (Exception e) {
|
|
217 |
// OK: attribute is not included in returned list, per spec
|
|
218 |
// XXX: log the exception
|
|
219 |
}
|
|
220 |
}
|
|
221 |
return result;
|
|
222 |
}
|
|
223 |
|
|
224 |
public final void setAttribute(Attribute attribute)
|
|
225 |
throws AttributeNotFoundException,
|
|
226 |
InvalidAttributeValueException,
|
|
227 |
MBeanException,
|
|
228 |
ReflectionException {
|
|
229 |
final String name = attribute.getName();
|
|
230 |
final Object value = attribute.getValue();
|
|
231 |
perInterface.setAttribute(resource, name, value, getCookie());
|
|
232 |
}
|
|
233 |
|
|
234 |
public final AttributeList setAttributes(AttributeList attributes) {
|
|
235 |
final AttributeList result = new AttributeList(attributes.size());
|
|
236 |
for (Object attrObj : attributes) {
|
|
237 |
// We can't use AttributeList.asList because it has side-effects
|
|
238 |
Attribute attr = (Attribute) attrObj;
|
|
239 |
try {
|
|
240 |
setAttribute(attr);
|
|
241 |
result.add(new Attribute(attr.getName(), attr.getValue()));
|
|
242 |
} catch (Exception e) {
|
|
243 |
// OK: attribute is not included in returned list, per spec
|
|
244 |
// XXX: log the exception
|
|
245 |
}
|
|
246 |
}
|
|
247 |
return result;
|
|
248 |
}
|
|
249 |
|
|
250 |
public final Object invoke(String operation, Object[] params,
|
|
251 |
String[] signature)
|
|
252 |
throws MBeanException, ReflectionException {
|
|
253 |
return perInterface.invoke(resource, operation, params, signature,
|
|
254 |
getCookie());
|
|
255 |
}
|
|
256 |
|
|
257 |
// Overridden by StandardMBeanSupport
|
|
258 |
public MBeanInfo getMBeanInfo() {
|
|
259 |
return mbeanInfo;
|
|
260 |
}
|
|
261 |
|
|
262 |
public final String getClassName() {
|
|
263 |
return resource.getClass().getName();
|
|
264 |
}
|
|
265 |
|
|
266 |
public final Object getResource() {
|
|
267 |
return resource;
|
|
268 |
}
|
|
269 |
|
|
270 |
public final Class<?> getMBeanInterface() {
|
|
271 |
return perInterface.getMBeanInterface();
|
|
272 |
}
|
|
273 |
|
|
274 |
private final MBeanInfo mbeanInfo;
|
|
275 |
private final Object resource;
|
|
276 |
private final PerInterface<M> perInterface;
|
|
277 |
}
|