Skip to content

Commit ca8ec3c

Browse files
committed
Absorb JDK-8054435 JEP prototype
1 parent 4e2975e commit ca8ec3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3663
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* Copyright (c) 2015, 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.annotations;
27+
28+
import com.sun.jmx.annotations.model.AttributeModel;
29+
import com.sun.jmx.annotations.model.MXBeanModel;
30+
import com.sun.jmx.annotations.model.OperationModel;
31+
import com.sun.jmx.annotations.model.InjectableFieldModel;
32+
import com.sun.jmx.mbeanserver.DynamicMBean2;
33+
import com.sun.jmx.mbeanserver.MXBeanMapping;
34+
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
35+
36+
import java.io.InvalidObjectException;
37+
import java.lang.invoke.MethodHandle;
38+
import java.lang.reflect.InvocationTargetException;
39+
import java.util.Arrays;
40+
import java.util.List;
41+
import java.util.concurrent.atomic.AtomicLong;
42+
import java.util.stream.Collectors;
43+
import javax.management.Attribute;
44+
import javax.management.AttributeList;
45+
import javax.management.AttributeNotFoundException;
46+
import javax.management.IntrospectionException;
47+
import javax.management.InvalidAttributeValueException;
48+
import javax.management.ListenerNotFoundException;
49+
import javax.management.MBeanException;
50+
import javax.management.MBeanInfo;
51+
import javax.management.MBeanNotificationInfo;
52+
import javax.management.Notification;
53+
import javax.management.NotificationBroadcasterSupport;
54+
import javax.management.NotificationEmitter;
55+
import javax.management.NotificationFilter;
56+
import javax.management.NotificationListener;
57+
import javax.management.ReflectionException;
58+
import javax.management.annotations.NotificationSender;
59+
import javax.management.annotations.NotificationInfos;
60+
import javax.management.modelmbean.ModelMBeanNotificationInfo;
61+
import javax.management.openmbean.CompositeData;
62+
import javax.management.openmbean.CompositeType;
63+
import javax.management.openmbean.OpenDataException;
64+
65+
66+
/**
67+
* A wrapper for the annotated MBeans. For the purposes of cooperation with
68+
* the rest of the JMX system the annotated MBean will behave like a
69+
* {@linkplain DynamicMBean2} and {@linkplain NotificationEmitter} instance.
70+
*
71+
*/
72+
abstract class AnnotatedMBean<T> implements DynamicMBean2, NotificationEmitter, NotificationSender {
73+
protected final MXBeanModel<T> model;
74+
protected final T instance;
75+
private NotificationBroadcasterSupport nbs = null;
76+
private final MBeanInfoBuilder mib;
77+
78+
protected AnnotatedMBean(MXBeanModel<T> model, T instance) throws IntrospectionException {
79+
this.model = model;
80+
this.instance = instance;
81+
this.mib = new MBeanInfoBuilder(model.getMappingFactory());
82+
injectFields();
83+
}
84+
85+
private void injectFields() throws IntrospectionException {
86+
for(InjectableFieldModel fm : model.getInjectableFields()) {
87+
if (fm.getType().isAssignableFrom(NotificationSender.class)) {
88+
// inject the NotificationSender instances
89+
fm.inject(instance, this);
90+
}
91+
}
92+
}
93+
94+
private synchronized NotificationBroadcasterSupport getNbs() {
95+
if (nbs == null) {
96+
List<ModelMBeanNotificationInfo> ntfs = model.getNotifications().stream()
97+
.map(mib::toNotificationInfo).collect(Collectors.toList());
98+
nbs = new NotificationBroadcasterSupport(ntfs.toArray(new ModelMBeanNotificationInfo[ntfs.size()]));
99+
}
100+
return nbs;
101+
}
102+
103+
@Override
104+
public Object getResource() {
105+
return this;
106+
}
107+
108+
@Override
109+
public String getClassName() {
110+
return model.getName();
111+
}
112+
113+
@Override
114+
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException {
115+
try {
116+
AttributeModel mam = model.getAttribute(attribute);
117+
if (mam == null) {
118+
throw new AttributeNotFoundException("Can not find attribute '" + attribute + "'");
119+
}
120+
MXBeanMapping m = getMapping(mam.getType());
121+
MethodHandle h = mam.getGetter().bindTo(instance);
122+
123+
Object[] args = new Object[h.type().parameterCount()];
124+
Class<?>[] paramTypes = h.type().parameterArray();
125+
for(int i=0;i<args.length;i++) {
126+
if (NotificationSender.class.isAssignableFrom(paramTypes[i])) {
127+
args[i] = this;
128+
}
129+
}
130+
Object val = args.length > 0 ? h.invokeWithArguments(args) : h.invoke();
131+
132+
return m != null ? m.toOpenValue(val) : val;
133+
} catch (Throwable t) {
134+
throw new MBeanException((Exception) t);
135+
}
136+
}
137+
138+
@Override
139+
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
140+
try {
141+
AttributeModel mam = model.getAttribute(attribute.getName());
142+
if (mam == null) {
143+
throw new AttributeNotFoundException();
144+
}
145+
MXBeanMapping m = getMapping(mam.getType());
146+
MethodHandle h = mam.getSetter().bindTo(instance);
147+
Object[] args = new Object[h.type().parameterCount()];
148+
Class<?>[] paramTypes = h.type().parameterArray();
149+
for(int i=0;i<args.length;i++) {
150+
if (paramTypes[i].equals(NotificationSender.class)) {
151+
h = h.bindTo(this);
152+
} else {
153+
h = h.bindTo(m != null ? m.fromOpenValue(attribute.getValue()) : attribute.getValue());
154+
}
155+
}
156+
h.invoke();
157+
} catch (Throwable t) {
158+
throw new MBeanException((Exception) t);
159+
}
160+
}
161+
162+
@Override
163+
public AttributeList getAttributes(String[] attributes) {
164+
AttributeList al = new AttributeList(attributes.length);
165+
for(String aName : attributes) {
166+
try {
167+
Object val = getAttribute(aName);
168+
al.add(new Attribute(aName, val));
169+
} catch (AttributeNotFoundException | MBeanException | ReflectionException ex) {
170+
// just ignore; method signature does not allow for exceptions
171+
}
172+
}
173+
return al;
174+
}
175+
176+
@Override
177+
public AttributeList setAttributes(AttributeList attributes) {
178+
AttributeList setAttrs = new AttributeList(attributes.size());
179+
for (Attribute a : attributes.asList()) {
180+
try {
181+
setAttribute(a);
182+
setAttrs.add(a);
183+
} catch (AttributeNotFoundException | MBeanException |
184+
ReflectionException | InvalidAttributeValueException ex) {
185+
// just ignore; method signature does not allow for exceptions
186+
}
187+
}
188+
return setAttrs;
189+
}
190+
191+
@Override
192+
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
193+
unwrapCompositeTypes(params, signature);
194+
195+
String type = Arrays.asList(signature).stream().collect(Collectors.joining(", ", "(", ")"));
196+
try {
197+
OperationModel mom = model.getOperation(actionName, type);
198+
if (mom == null) {
199+
throw new MBeanException(null, "Unknown operation: " + actionName);
200+
}
201+
MXBeanMapping m = getMapping(mom.getType());
202+
203+
MethodHandle mh = mom.getMethodHandle().bindTo(instance);
204+
205+
java.lang.reflect.Parameter[] mParams = mom.getMethod().getParameters();
206+
Object[] transParams = new Object[mom.getMethod().getParameterCount()];
207+
208+
for(int pIndex = 0, tIndex = 0;tIndex<transParams.length;tIndex++) {
209+
if (NotificationSender.class.isAssignableFrom(mParams[tIndex].getType()) && (
210+
mParams[tIndex].isAnnotationPresent(NotificationInfos.class) ||
211+
mParams[tIndex].isAnnotationPresent(javax.management.annotations.NotificationInfo.class))) {
212+
transParams[tIndex] = this;
213+
} else {
214+
java.lang.reflect.Parameter p = mParams[tIndex];
215+
MXBeanMapping map = getMapping(p.getType());
216+
Object val = params[pIndex++];
217+
transParams[tIndex] = map != null ? map.fromOpenValue(val) : val;
218+
}
219+
}
220+
221+
Object val = mh.invokeWithArguments(transParams);
222+
return m != null ? m.toOpenValue(val) : val;
223+
} catch (OpenDataException | InvalidObjectException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
224+
throw new MBeanException(e);
225+
} catch (Throwable t) {
226+
throw new MBeanException(new InvocationTargetException(t));
227+
}
228+
}
229+
230+
@Override
231+
public MBeanInfo getMBeanInfo() {
232+
return mib.toMBeanInfo(model);
233+
}
234+
235+
@Override
236+
final public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
237+
getNbs().addNotificationListener(listener, filter, handback);
238+
}
239+
240+
@Override
241+
final public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
242+
getNbs().removeNotificationListener(listener);
243+
}
244+
245+
@Override
246+
final public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException {
247+
getNbs().removeNotificationListener(listener, filter, handback);
248+
}
249+
250+
@Override
251+
final public MBeanNotificationInfo[] getNotificationInfo() {
252+
return getNbs().getNotificationInfo();
253+
}
254+
255+
@Override
256+
final public void sendNotification(Notification notification) {
257+
getNbs().sendNotification(notification);
258+
}
259+
260+
private final AtomicLong notifCounter = new AtomicLong();
261+
262+
@Override
263+
public void sendNotification(String type, String message, Object userData) {
264+
Notification n = new Notification(type, this, notifCounter.getAndIncrement(), message);
265+
n.setUserData(userData);
266+
nbs.sendNotification(n);
267+
}
268+
269+
private MXBeanMapping getMapping(Class<?> type) throws OpenDataException {
270+
return model.getMappingFactory().mappingForType(type, MXBeanMappingFactory.DEFAULT);
271+
}
272+
273+
private void unwrapCompositeTypes(Object[] params, String[] signature) {
274+
if (params != null) {
275+
for(int i=0;i<params.length;i++) {
276+
if (signature[i].equals(CompositeData.class.getName())) {
277+
CompositeType ct = ((CompositeData)params[i]).getCompositeType();
278+
signature[i] = ct.getTypeName();
279+
}
280+
}
281+
}
282+
}
283+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2015, 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.annotations;
27+
28+
import com.sun.jmx.annotations.model.MXBeanModel;
29+
30+
import java.security.Permission;
31+
import java.util.Iterator;
32+
import java.util.ServiceLoader;
33+
import javax.management.DynamicMBean;
34+
import javax.management.IntrospectionException;
35+
36+
/**
37+
* This introspector will turn an annotated MBean class into a compliant
38+
* {@linkplain DynamicMBean} implementation.
39+
*/
40+
public class AnnotatedMBeanIntrospector {
41+
private static final Permission CSJAM_ACCESS = new RuntimePermission("accessClassInPackage.com.sun.jmx.annotations.model");
42+
43+
private volatile static ModelBuilder builder = null;
44+
45+
/**
46+
* Takes an instance and tries to convert it to a {@linkplain DynamicMBean} implementation
47+
* according to any present {@link javax.management.annotations} annotations.
48+
*
49+
* @param <T> The type of the given instance
50+
* @param instance The instance
51+
* @return An {@linkplain DynamicMBean} wrapper or null when the provided instance
52+
* is not properly annotated.
53+
*
54+
* @throws IntrospectionException
55+
*/
56+
public static <T> DynamicMBean toMBean(T instance) throws IntrospectionException {
57+
ModelBuilder mb = getBuilder();
58+
if (mb != null) {
59+
MXBeanModel<T> m = mb.buildModel(instance.getClass());
60+
if (m != null) {
61+
return new RegisteringAnnotatedMBean<>(m, instance);
62+
}
63+
return null;
64+
}
65+
throw new IntrospectionException("An appropriate MXBean Model Builder can not be located.");
66+
}
67+
68+
private static ModelBuilder getBuilder() {
69+
if (builder == null) {
70+
ServiceLoader<ModelBuilder> l = ServiceLoader.load(ModelBuilder.class);
71+
Iterator<ModelBuilder> svcIter = l.iterator();
72+
if (svcIter.hasNext()) {
73+
builder = svcIter.next();
74+
}
75+
}
76+
return builder;
77+
}
78+
}

0 commit comments

Comments
 (0)