Skip to content
This repository has been archived by the owner on Jul 13, 2022. It is now read-only.

Commit

Permalink
Add support for Boot 2.0 endpoints in JMXActuatorClient
Browse files Browse the repository at this point in the history
  • Loading branch information
kdvolder committed Sep 14, 2017
1 parent 5e4e6ef commit 9593947
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
import java.util.Set;

import javax.inject.Provider;
import javax.management.InstanceNotFoundException;

import org.springframework.ide.eclipse.boot.launch.util.JMXClient;
import org.springsource.ide.eclipse.commons.frameworks.core.ExceptionUtil;
import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableSet;
Expand All @@ -28,10 +29,22 @@
*/
public class JMXActuatorClient extends ActuatorClient {

private static final String OBJECT_NAME = "org.springframework.boot:type=Endpoint,name=requestMappingEndpoint";
private static final String ATTRIBUTE_NAME = "Data";
private final Provider<Integer> portProvider;

static class OperationInfo {
final String objectName;
final String operationName;
public OperationInfo(String objectName, String operationName) {
this.objectName = objectName;
this.operationName = operationName;
}
}

private static final OperationInfo[] OPERATIONS = {
new OperationInfo("org.springframework.boot:type=Endpoint,name=Mappings", "mappings"), //Boot 2.x
new OperationInfo("org.springframework.boot:type=Endpoint,name=requestMappingEndpoint", "getData") //Boot 1.x
};

private JMXClient client = null;
private Integer port = null;

Expand All @@ -45,14 +58,19 @@ protected String getRequestMappingData() throws Exception {
try {
JMXClient client = getClient();
if (client!=null) {
Object obj = client.getAttribute(ATTRIBUTE_NAME);
if (obj!=null) {
//TODO: Can we avoid conversion to string only to parse it again later?
return new ObjectMapper().writeValueAsString(obj);
for (OperationInfo op : OPERATIONS) {
try {
Object obj = client.callOperation(op.objectName, op.operationName);
if (obj!=null) {
return new ObjectMapper().writeValueAsString(obj);
}
} catch (InstanceNotFoundException e) {
//Ignore and try other mbean
}
}
}
} catch (Exception e) {
disposeClient();
disposeClient(); //Client may be in broken state, do not reuse.
if (!isExpectedException(e)) {
throw e;
}
Expand All @@ -77,7 +95,7 @@ private synchronized JMXClient getClient() throws Exception {
if (!currentPort.equals(port) || client==null) {
disposeClient();
port = currentPort;
client = new JMXClient(currentPort, OBJECT_NAME);
client = new JMXClient(currentPort);
}
return client;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,25 @@
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;

/**
* A JMX client for interacting with specific mbean.
* A JMX client for interacting with mbeans.
*
* @author Stephane Nicoll
* @author Kris De Volder
*/
public class JMXClient implements Disposable {

private static final Object[] NO_PARAMS = new Object[0];
private static final String[] NO_SIGNATURES = new String[0];

private JMXConnector connector;
private MBeanServerConnection connection;
private ObjectName objectName;

public JMXClient(int port, String objectName) throws IOException {
this(createLocalJmxConnector(port), objectName);
public JMXClient(int port) throws IOException {
this(createLocalJmxConnector(port));
}

private JMXClient(JMXConnector connector, String objectName) throws IOException {
this(connector, connector.getMBeanServerConnection(), objectName);
private JMXClient(JMXConnector connector) throws IOException {
this(connector, connector.getMBeanServerConnection());
}

@Override
Expand All @@ -54,26 +56,30 @@ public void dispose() {
}
}

private JMXClient(JMXConnector connector, MBeanServerConnection connection, String objectName) {
private JMXClient(JMXConnector connector, MBeanServerConnection connection) {
this.connector = connector;
this.connection = connection;
this.objectName = toObjectName(objectName);
}

@SuppressWarnings("unchecked")
public <T> T getAttribute(Class<T> klass, String attributeName) throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException, IOException {
Object value = getAttribute(attributeName);
public <T> T getAttribute(Class<T> klass, String objectName, String attributeName) throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException, IOException {
Object value = getAttribute(objectName, attributeName);
if (value==null || klass.isInstance(value)) {
return (T)value;
} else {
throw new ClassCastException("Value '"+value+"' can't be cast to "+klass);
}
}

public Object getAttribute(String attributeName) throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException, IOException {
return this.connection.getAttribute(objectName, attributeName);
public Object getAttribute(String objectName, String attributeName) throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException, IOException {
return this.connection.getAttribute(toObjectName(objectName), attributeName);
}

public Object callOperation(String objectName, String operationName) throws InstanceNotFoundException, MBeanException, ReflectionException, IOException {
return this.connection.invoke(toObjectName(objectName), operationName, NO_PARAMS, NO_SIGNATURES);
}


private ObjectName toObjectName(String name) {
try {
return new ObjectName(name);
Expand Down

0 comments on commit 9593947

Please sign in to comment.