package com.oracle.svm.core.jdk.management;
import java.lang.management.ClassLoadingMXBean;
import java.lang.management.CompilationMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.PlatformManagedObject;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.management.MBeanServerBuilder;
import javax.management.openmbean.OpenType;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.jdk.JNIRegistrationUtil;
import com.oracle.svm.core.jdk.RuntimeFeature;
import com.oracle.svm.util.ReflectionUtil;
@AutomaticFeature
public final class ManagementFeature extends JNIRegistrationUtil implements Feature {
private Map<PlatformManagedObject, PlatformManagedObject> platformManagedObjectReplacements;
@Override
public List<Class<? extends Feature>> getRequiredFeatures() {
return Collections.singletonList(RuntimeFeature.class);
}
@Override
public void afterRegistration(AfterRegistrationAccess access) {
ImageSingletons.add(ManagementSupport.class, new ManagementSupport());
}
@Override
public void duringSetup(DuringSetupAccess access) {
platformManagedObjectReplacements = new IdentityHashMap<>();
for (Class<? extends PlatformManagedObject> clazz : Arrays.asList(ClassLoadingMXBean.class, CompilationMXBean.class, RuntimeMXBean.class,
ThreadMXBean.class, OperatingSystemMXBean.class, MemoryMXBean.class)) {
PlatformManagedObject source = ManagementFactory.getPlatformMXBean(clazz);
PlatformManagedObject target = (PlatformManagedObject) ManagementSupport.getSingleton().platformManagedObjectsMap.get(clazz);
if (source != null && target != null) {
platformManagedObjectReplacements.put(source, target);
}
}
access.registerObjectReplacer(this::replaceHostedPlatformManagedObject);
RuntimeClassInitialization.initializeAtBuildTime("com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory", "Avoids unnecessary reflection in the image");
}
private Object replaceHostedPlatformManagedObject(Object source) {
if (source instanceof PlatformManagedObject) {
Object replacement = platformManagedObjectReplacements.get(source);
if (replacement != null) {
return replacement;
}
}
return source;
}
@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
access.registerReachabilityHandler(ManagementFeature::registerMBeanServerFactoryNewBuilder, method(access, "javax.management.MBeanServerFactory", "newBuilder", Class.class));
access.registerReachabilityHandler(ManagementFeature::registerMXBeanMappingMakeOpenClass, method(access, "com.sun.jmx.mbeanserver.MXBeanMapping", "makeOpenClass", Type.class, OpenType.class));
}
private static void registerMBeanServerFactoryNewBuilder(@SuppressWarnings("unused") DuringAnalysisAccess a) {
RuntimeReflection.register(ReflectionUtil.lookupConstructor(MBeanServerBuilder.class));
}
private static void registerMXBeanMappingMakeOpenClass(DuringAnalysisAccess access) {
for (String className : OpenType.ALLOWED_CLASSNAMES_LIST) {
RuntimeReflection.register(clazz(access, className));
RuntimeReflection.register(clazz(access, "[L" + className + ";"));
}
}
}