forked from openjdk/jdk
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
43 changed files
with
3,663 additions
and
8 deletions.
There are no files selected for viewing
283 changes: 283 additions & 0 deletions
283
src/java.management/share/classes/com/sun/jmx/annotations/AnnotatedMBean.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
/* | ||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. Oracle designates this | ||
* particular file as subject to the "Classpath" exception as provided | ||
* by Oracle in the LICENSE file that accompanied this code. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
package com.sun.jmx.annotations; | ||
|
||
import com.sun.jmx.annotations.model.AttributeModel; | ||
import com.sun.jmx.annotations.model.MXBeanModel; | ||
import com.sun.jmx.annotations.model.OperationModel; | ||
import com.sun.jmx.annotations.model.InjectableFieldModel; | ||
import com.sun.jmx.mbeanserver.DynamicMBean2; | ||
import com.sun.jmx.mbeanserver.MXBeanMapping; | ||
import com.sun.jmx.mbeanserver.MXBeanMappingFactory; | ||
|
||
import java.io.InvalidObjectException; | ||
import java.lang.invoke.MethodHandle; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.concurrent.atomic.AtomicLong; | ||
import java.util.stream.Collectors; | ||
import javax.management.Attribute; | ||
import javax.management.AttributeList; | ||
import javax.management.AttributeNotFoundException; | ||
import javax.management.IntrospectionException; | ||
import javax.management.InvalidAttributeValueException; | ||
import javax.management.ListenerNotFoundException; | ||
import javax.management.MBeanException; | ||
import javax.management.MBeanInfo; | ||
import javax.management.MBeanNotificationInfo; | ||
import javax.management.Notification; | ||
import javax.management.NotificationBroadcasterSupport; | ||
import javax.management.NotificationEmitter; | ||
import javax.management.NotificationFilter; | ||
import javax.management.NotificationListener; | ||
import javax.management.ReflectionException; | ||
import javax.management.annotations.NotificationSender; | ||
import javax.management.annotations.NotificationInfos; | ||
import javax.management.modelmbean.ModelMBeanNotificationInfo; | ||
import javax.management.openmbean.CompositeData; | ||
import javax.management.openmbean.CompositeType; | ||
import javax.management.openmbean.OpenDataException; | ||
|
||
|
||
/** | ||
* A wrapper for the annotated MBeans. For the purposes of cooperation with | ||
* the rest of the JMX system the annotated MBean will behave like a | ||
* {@linkplain DynamicMBean2} and {@linkplain NotificationEmitter} instance. | ||
* | ||
*/ | ||
abstract class AnnotatedMBean<T> implements DynamicMBean2, NotificationEmitter, NotificationSender { | ||
protected final MXBeanModel<T> model; | ||
protected final T instance; | ||
private NotificationBroadcasterSupport nbs = null; | ||
private final MBeanInfoBuilder mib; | ||
|
||
protected AnnotatedMBean(MXBeanModel<T> model, T instance) throws IntrospectionException { | ||
this.model = model; | ||
this.instance = instance; | ||
this.mib = new MBeanInfoBuilder(model.getMappingFactory()); | ||
injectFields(); | ||
} | ||
|
||
private void injectFields() throws IntrospectionException { | ||
for(InjectableFieldModel fm : model.getInjectableFields()) { | ||
if (fm.getType().isAssignableFrom(NotificationSender.class)) { | ||
// inject the NotificationSender instances | ||
fm.inject(instance, this); | ||
} | ||
} | ||
} | ||
|
||
private synchronized NotificationBroadcasterSupport getNbs() { | ||
if (nbs == null) { | ||
List<ModelMBeanNotificationInfo> ntfs = model.getNotifications().stream() | ||
.map(mib::toNotificationInfo).collect(Collectors.toList()); | ||
nbs = new NotificationBroadcasterSupport(ntfs.toArray(new ModelMBeanNotificationInfo[ntfs.size()])); | ||
} | ||
return nbs; | ||
} | ||
|
||
@Override | ||
public Object getResource() { | ||
return this; | ||
} | ||
|
||
@Override | ||
public String getClassName() { | ||
return model.getName(); | ||
} | ||
|
||
@Override | ||
public Object getAttribute(String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { | ||
try { | ||
AttributeModel mam = model.getAttribute(attribute); | ||
if (mam == null) { | ||
throw new AttributeNotFoundException("Can not find attribute '" + attribute + "'"); | ||
} | ||
MXBeanMapping m = getMapping(mam.getType()); | ||
MethodHandle h = mam.getGetter().bindTo(instance); | ||
|
||
Object[] args = new Object[h.type().parameterCount()]; | ||
Class<?>[] paramTypes = h.type().parameterArray(); | ||
for(int i=0;i<args.length;i++) { | ||
if (NotificationSender.class.isAssignableFrom(paramTypes[i])) { | ||
args[i] = this; | ||
} | ||
} | ||
Object val = args.length > 0 ? h.invokeWithArguments(args) : h.invoke(); | ||
|
||
return m != null ? m.toOpenValue(val) : val; | ||
} catch (Throwable t) { | ||
throw new MBeanException((Exception) t); | ||
} | ||
} | ||
|
||
@Override | ||
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { | ||
try { | ||
AttributeModel mam = model.getAttribute(attribute.getName()); | ||
if (mam == null) { | ||
throw new AttributeNotFoundException(); | ||
} | ||
MXBeanMapping m = getMapping(mam.getType()); | ||
MethodHandle h = mam.getSetter().bindTo(instance); | ||
Object[] args = new Object[h.type().parameterCount()]; | ||
Class<?>[] paramTypes = h.type().parameterArray(); | ||
for(int i=0;i<args.length;i++) { | ||
if (paramTypes[i].equals(NotificationSender.class)) { | ||
h = h.bindTo(this); | ||
} else { | ||
h = h.bindTo(m != null ? m.fromOpenValue(attribute.getValue()) : attribute.getValue()); | ||
} | ||
} | ||
h.invoke(); | ||
} catch (Throwable t) { | ||
throw new MBeanException((Exception) t); | ||
} | ||
} | ||
|
||
@Override | ||
public AttributeList getAttributes(String[] attributes) { | ||
AttributeList al = new AttributeList(attributes.length); | ||
for(String aName : attributes) { | ||
try { | ||
Object val = getAttribute(aName); | ||
al.add(new Attribute(aName, val)); | ||
} catch (AttributeNotFoundException | MBeanException | ReflectionException ex) { | ||
// just ignore; method signature does not allow for exceptions | ||
} | ||
} | ||
return al; | ||
} | ||
|
||
@Override | ||
public AttributeList setAttributes(AttributeList attributes) { | ||
AttributeList setAttrs = new AttributeList(attributes.size()); | ||
for (Attribute a : attributes.asList()) { | ||
try { | ||
setAttribute(a); | ||
setAttrs.add(a); | ||
} catch (AttributeNotFoundException | MBeanException | | ||
ReflectionException | InvalidAttributeValueException ex) { | ||
// just ignore; method signature does not allow for exceptions | ||
} | ||
} | ||
return setAttrs; | ||
} | ||
|
||
@Override | ||
public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException { | ||
unwrapCompositeTypes(params, signature); | ||
|
||
String type = Arrays.asList(signature).stream().collect(Collectors.joining(", ", "(", ")")); | ||
try { | ||
OperationModel mom = model.getOperation(actionName, type); | ||
if (mom == null) { | ||
throw new MBeanException(null, "Unknown operation: " + actionName); | ||
} | ||
MXBeanMapping m = getMapping(mom.getType()); | ||
|
||
MethodHandle mh = mom.getMethodHandle().bindTo(instance); | ||
|
||
java.lang.reflect.Parameter[] mParams = mom.getMethod().getParameters(); | ||
Object[] transParams = new Object[mom.getMethod().getParameterCount()]; | ||
|
||
for(int pIndex = 0, tIndex = 0;tIndex<transParams.length;tIndex++) { | ||
if (NotificationSender.class.isAssignableFrom(mParams[tIndex].getType()) && ( | ||
mParams[tIndex].isAnnotationPresent(NotificationInfos.class) || | ||
mParams[tIndex].isAnnotationPresent(javax.management.annotations.NotificationInfo.class))) { | ||
transParams[tIndex] = this; | ||
} else { | ||
java.lang.reflect.Parameter p = mParams[tIndex]; | ||
MXBeanMapping map = getMapping(p.getType()); | ||
Object val = params[pIndex++]; | ||
transParams[tIndex] = map != null ? map.fromOpenValue(val) : val; | ||
} | ||
} | ||
|
||
Object val = mh.invokeWithArguments(transParams); | ||
return m != null ? m.toOpenValue(val) : val; | ||
} catch (OpenDataException | InvalidObjectException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | ||
throw new MBeanException(e); | ||
} catch (Throwable t) { | ||
throw new MBeanException(new InvocationTargetException(t)); | ||
} | ||
} | ||
|
||
@Override | ||
public MBeanInfo getMBeanInfo() { | ||
return mib.toMBeanInfo(model); | ||
} | ||
|
||
@Override | ||
final public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) { | ||
getNbs().addNotificationListener(listener, filter, handback); | ||
} | ||
|
||
@Override | ||
final public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { | ||
getNbs().removeNotificationListener(listener); | ||
} | ||
|
||
@Override | ||
final public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { | ||
getNbs().removeNotificationListener(listener, filter, handback); | ||
} | ||
|
||
@Override | ||
final public MBeanNotificationInfo[] getNotificationInfo() { | ||
return getNbs().getNotificationInfo(); | ||
} | ||
|
||
@Override | ||
final public void sendNotification(Notification notification) { | ||
getNbs().sendNotification(notification); | ||
} | ||
|
||
private final AtomicLong notifCounter = new AtomicLong(); | ||
|
||
@Override | ||
public void sendNotification(String type, String message, Object userData) { | ||
Notification n = new Notification(type, this, notifCounter.getAndIncrement(), message); | ||
n.setUserData(userData); | ||
nbs.sendNotification(n); | ||
} | ||
|
||
private MXBeanMapping getMapping(Class<?> type) throws OpenDataException { | ||
return model.getMappingFactory().mappingForType(type, MXBeanMappingFactory.DEFAULT); | ||
} | ||
|
||
private void unwrapCompositeTypes(Object[] params, String[] signature) { | ||
if (params != null) { | ||
for(int i=0;i<params.length;i++) { | ||
if (signature[i].equals(CompositeData.class.getName())) { | ||
CompositeType ct = ((CompositeData)params[i]).getCompositeType(); | ||
signature[i] = ct.getTypeName(); | ||
} | ||
} | ||
} | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/java.management/share/classes/com/sun/jmx/annotations/AnnotatedMBeanIntrospector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. | ||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
* | ||
* This code is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 only, as | ||
* published by the Free Software Foundation. Oracle designates this | ||
* particular file as subject to the "Classpath" exception as provided | ||
* by Oracle in the LICENSE file that accompanied this code. | ||
* | ||
* This code is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
* version 2 for more details (a copy is included in the LICENSE file that | ||
* accompanied this code). | ||
* | ||
* You should have received a copy of the GNU General Public License version | ||
* 2 along with this work; if not, write to the Free Software Foundation, | ||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
* | ||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | ||
* or visit www.oracle.com if you need additional information or have any | ||
* questions. | ||
*/ | ||
|
||
package com.sun.jmx.annotations; | ||
|
||
import com.sun.jmx.annotations.model.MXBeanModel; | ||
|
||
import java.security.Permission; | ||
import java.util.Iterator; | ||
import java.util.ServiceLoader; | ||
import javax.management.DynamicMBean; | ||
import javax.management.IntrospectionException; | ||
|
||
/** | ||
* This introspector will turn an annotated MBean class into a compliant | ||
* {@linkplain DynamicMBean} implementation. | ||
*/ | ||
public class AnnotatedMBeanIntrospector { | ||
private static final Permission CSJAM_ACCESS = new RuntimePermission("accessClassInPackage.com.sun.jmx.annotations.model"); | ||
|
||
private volatile static ModelBuilder builder = null; | ||
|
||
/** | ||
* Takes an instance and tries to convert it to a {@linkplain DynamicMBean} implementation | ||
* according to any present {@link javax.management.annotations} annotations. | ||
* | ||
* @param <T> The type of the given instance | ||
* @param instance The instance | ||
* @return An {@linkplain DynamicMBean} wrapper or null when the provided instance | ||
* is not properly annotated. | ||
* | ||
* @throws IntrospectionException | ||
*/ | ||
public static <T> DynamicMBean toMBean(T instance) throws IntrospectionException { | ||
ModelBuilder mb = getBuilder(); | ||
if (mb != null) { | ||
MXBeanModel<T> m = mb.buildModel(instance.getClass()); | ||
if (m != null) { | ||
return new RegisteringAnnotatedMBean<>(m, instance); | ||
} | ||
return null; | ||
} | ||
throw new IntrospectionException("An appropriate MXBean Model Builder can not be located."); | ||
} | ||
|
||
private static ModelBuilder getBuilder() { | ||
if (builder == null) { | ||
ServiceLoader<ModelBuilder> l = ServiceLoader.load(ModelBuilder.class); | ||
Iterator<ModelBuilder> svcIter = l.iterator(); | ||
if (svcIter.hasNext()) { | ||
builder = svcIter.next(); | ||
} | ||
} | ||
return builder; | ||
} | ||
} |
Oops, something went wrong.