scylla-jmx: Make scylla-jmx compatible with jdk9+

Adds explicit maven dependecies for libraries
removed from JDK.
Removes reflection calls forbidden in jdk9+.

Message-Id: <20181120142550.22852-1-calle@scylladb.com>
This commit is contained in:
Calle Wilund 2018-11-20 14:25:50 +00:00 committed by Avi Kivity
parent 854e6072a2
commit 9eec9eabf6
2 changed files with 44 additions and 18 deletions

View File

@ -76,6 +76,11 @@
<artifactId>google-collections</artifactId> <artifactId>google-collections</artifactId>
<version>1.0</version> <version>1.0</version>
</dependency> </dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

View File

@ -4,9 +4,13 @@ package com.scylladb.jmx.utils;
*/ */
import static com.scylladb.jmx.main.Main.client; import static com.scylladb.jmx.main.Main.client;
import static com.sun.jmx.mbeanserver.Util.wildmatch;
import static java.util.logging.Level.SEVERE; import static java.util.logging.Level.SEVERE;
import static javax.management.MBeanServerDelegate.DELEGATE_NAME;
import java.lang.reflect.Field; import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -45,8 +49,14 @@ import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
import com.sun.jmx.mbeanserver.JmxMBeanServer; import com.sun.jmx.mbeanserver.JmxMBeanServer;
import com.sun.jmx.mbeanserver.NamedObject; import com.sun.jmx.mbeanserver.NamedObject;
import com.sun.jmx.mbeanserver.Repository; import com.sun.jmx.mbeanserver.Repository;
import com.sun.jmx.mbeanserver.Util;
/**
* This class purposly knows way to much of the inner workings
* of Oracle JDK MBeanServer workings, and pervert it for
* performance sakes. It is not portable to other MBean implementations.
*
*/
@SuppressWarnings("restriction")
public class APIBuilder extends MBeanServerBuilder { public class APIBuilder extends MBeanServerBuilder {
private static final Logger logger = Logger.getLogger(APIBuilder.class.getName()); private static final Logger logger = Logger.getLogger(APIBuilder.class.getName());
@ -269,7 +279,7 @@ public class APIBuilder extends MBeanServerBuilder {
// Pattern matching in the domain name (*, ?) // Pattern matching in the domain name (*, ?)
final String dom2Match = name.getDomain(); final String dom2Match = name.getDomain();
if (Util.wildmatch(TableMetricParams.TABLE_METRICS_DOMAIN, dom2Match)) { if (wildmatch(TableMetricParams.TABLE_METRICS_DOMAIN, dom2Match)) {
if (allNames) { if (allNames) {
addAll(res); addAll(res);
} else { } else {
@ -376,7 +386,7 @@ public class APIBuilder extends MBeanServerBuilder {
// wildmatch key property values // wildmatch key property values
// values[i] is the pattern; // values[i] is the pattern;
// v is the string // v is the string
if (Util.wildmatch(v,values[i])) { if (wildmatch(v,values[i])) {
continue; continue;
} else { } else {
return false; return false;
@ -451,25 +461,36 @@ public class APIBuilder extends MBeanServerBuilder {
@Override @Override
public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) { public MBeanServer newMBeanServer(String defaultDomain, MBeanServer outer, MBeanServerDelegate delegate) {
// It is important to set |interceptors| to true while creating the JmxMBeanSearver. // It is important to set |interceptors| to true while creating the
// It is required for calls to JmxMBeanServer.getMBeanServerInterceptor() to be allowed. // JmxMBeanSearver. It is required for calls to
// JmxMBeanServer.setMBeanServerInterceptor() to be allowed.
JmxMBeanServer nested = (JmxMBeanServer) JmxMBeanServer.newMBeanServer(defaultDomain, outer, delegate, true); JmxMBeanServer nested = (JmxMBeanServer) JmxMBeanServer.newMBeanServer(defaultDomain, outer, delegate, true);
DefaultMBeanServerInterceptor interceptor = (DefaultMBeanServerInterceptor) nested.getMBeanServerInterceptor(); // This is not very clean, we depend on knowledge of how the Sun/Oracle
Field repoField; // MBean chain looks internally. But we need haxxor support, so
// lets replace the interceptor.
// Note: Removed reflection gunk to eliminate jdk9+ warnings on
// execution. Also, if we can get by without reflection, it is
// better.
final DefaultMBeanServerInterceptor interceptor = new DefaultMBeanServerInterceptor(outer != null ? outer : nested,
delegate, nested.getMBeanInstantiator(),
new TableRepository(defaultDomain, new Repository(defaultDomain)));
nested.setMBeanServerInterceptor(interceptor);
final MBeanServerDelegate d = nested.getMBeanServerDelegate();
try { try {
repoField = DefaultMBeanServerInterceptor.class.getDeclaredField("repository"); // Interceptor needs the delegate present. Normally done
} catch (NoSuchFieldException | SecurityException e) { // by inaccessible method in JmxMBeanServer
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
interceptor.registerMBean(d, DELEGATE_NAME);
return null;
}
});
} catch (PrivilegedActionException e) {
logger.log(SEVERE, "Unexpected error.", e); logger.log(SEVERE, "Unexpected error.", e);
throw new RuntimeException(e); throw new RuntimeException(e);
} }
repoField.setAccessible(true);
try {
final Repository repository = (Repository)repoField.get(interceptor);
repoField.set(interceptor, new TableRepository(defaultDomain, repository));
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.log(SEVERE, "Unexpected error.", e);
new RuntimeException(e);
}
return new APIMBeanServer(client, nested); return new APIMBeanServer(client, nested);
} }
} }