Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion java/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Usage
------

```
jmxquery [-url] [-username,u] [-password,p] [-query,q] [-incjvm] [-json] [-help]
jmxquery [-url] [-username,u] [-password,p] [-query,q] [-call,c] [-incjvm] [-json] [-help]
```

options are:
Expand All @@ -33,6 +33,12 @@ options are:
{attributeKey} is optional and only used for Composite metric types.
Use semi-colon to separate metrics.

-call, c
Call a method using a base64 encoded JSON as parameter
JSON format:
{"objectName":"{mBeanName}","name":"{methodName}","params":[{"value":"{value}","type":"{type}"},...]}
Supported types: char, short, int, long, boolean, double, float, String, Float, Double, Short, Int, Long

-incjvm
Will add all standard JVM metrics to the -metrics query if used under java.lang domain
Useful utility function to add JVM metrics quickly and also for testing connections if
Expand Down Expand Up @@ -79,6 +85,12 @@ You can get multiple values by joining the mbeans together with semi colons.
java -jar JMXQuery.jar -url service:jmx:rmi:///jndi/rmi://localhost:1616/jmxrmi -q "java.lang:type=ClassLoading/LoadedClassCount;java.lang:type=ClassLoading/UnloadedClassCount"
```

```
Invoke the add method: {"objectName":"com.outlyer.jmx.jmxquery.app.tests:type=Test","name":"add","params":[{"value":"Test ","type":"String"},{"value":"test","type":"String"}]}

java -jar JMXQuery.jar -url service:jmx:rmi:///jndi/rmi://localhost:1616/jmxrmi -c eyJvYmplY3ROYW1lIjoiY29tLm91dGx5ZXIuam14LmpteHF1ZXJ5LmFwcC50ZXN0czp0eXBlPVRlc3QiLCJuYW1lIjoiYWRkIiwicGFyYW1zIjpbeyJ2YWx1ZSI6IlRlc3QgIiwidHlwZSI6IlN0cmluZyJ9LHsidmFsdWUiOiJ0ZXN0IiwidHlwZSI6IlN0cmluZyJ9XX0=

```
Building the Jar
----------------

Expand Down
5 changes: 5 additions & 0 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<scope>system</scope>
<systemPath>${toolsjar}</systemPath>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
</dependencies>

<build>
Expand Down
73 changes: 72 additions & 1 deletion java/src/main/java/com/outlyer/jmx/jmxquery/JMXConnector.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import com.outlyer.jmx.jmxquery.tools.JMXTools;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
Expand Down Expand Up @@ -108,6 +111,74 @@ public void disconnect() throws IOException {
}
}

/**
* invokes a method on the server using JMX
*
* @param name
* - The object name of the MBean on which the method is to be
* invoked.
* @param method
* - The name of the method to be invoked.
* @param args
* - An array containing the arguments of the method to be set
* when the operation is invoked
* @param signatures
* - An array containing the signatures of the arguments, an
* array of class names in the format returned by
* Class.getName().
* @return result of invoking the operation on the MBean specified
* @throws java.io.IOException
* @throws javax.management.MalformedObjectNameException
* @throws javax.management.InstanceNotFoundException
* @throws javax.management.IntrospectionException
* @throws javax.management.ReflectionException
* @throws MBeanException
*/
public Object invoke(String objectName, String method, Object[] args, String[] signatures)
throws IOException, MalformedObjectNameException, InstanceNotFoundException, IntrospectionException,
ReflectionException, MBeanException {
return connection.invoke(new ObjectName(objectName), method, args, signatures);
}

/**
* set an attribute on the server using JMX
*
* @param name
* - The object name of the MBean on which the method is to be
* invoked.
* @param field
* - The name of the field to be invoked.
* @param value
* - A value of type parameter
* @return void
* @throws java.io.IOException
* @throws javax.management.MalformedObjectNameException
* @throws javax.management.InstanceNotFoundException
* @throws javax.management.IntrospectionException
* @throws javax.management.ReflectionException
* @throws MBeanException
* @throws InvalidAttributeValueException
* @throws AttributeNotFoundException
*/
public void set(String objectName, String field, Object value)
throws IOException, MalformedObjectNameException, InstanceNotFoundException, IntrospectionException,
ReflectionException, MBeanException, AttributeNotFoundException, InvalidAttributeValueException {
connection.setAttribute(new ObjectName(objectName), new Attribute(field,value));
}

/**
* query the actual name of the MBean
*
* @param name
* - The object search string.
* @return actual name of the MBean
* @throws java.io.IOException
* @throws javax.management.MalformedObjectNameException
*/
public ObjectName queryName(String name) throws MalformedObjectNameException, IOException {
return connection.queryNames(new ObjectName(name), null).iterator().next();
}

/**
* Fetches a list of metrics and their values in one go
*
Expand Down
42 changes: 33 additions & 9 deletions java/src/main/java/com/outlyer/jmx/jmxquery/JMXMetric.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,42 @@ public String toString() {
s += " (" + attributeType + ")";
}
if (value != null) {
s += " = " + value.toString();
if (value instanceof String) {
s += " = " + value.toString();
} else {
s += " = " + valueToString(value);
}
}

return s;
}

private static String valueToString(Object value) {
if (value == null) {
return "null";
}
if (value.getClass().isArray()) {
return arrayToString((Object[]) value);
}
if ((value instanceof Integer) || (value instanceof Long) || (value instanceof Double)
|| (value instanceof Boolean)) {
return value.toString();
}
return new StringBuilder().append("\"").append(value).append("\"").toString();
}

private static String arrayToString(Object[] array) {
String s = "[";
boolean separatorRequired = false;
for (Object v : array) {
if (separatorRequired)
s += ",";
separatorRequired = true;
s += valueToString(v);
}
s += "]";
return s;
}

/**
* Returns JSON representation of metric
Expand Down Expand Up @@ -326,14 +357,7 @@ public String toJSON() {
json += ", \"attributeType\" : \"" + this.attributeType + "\"";
}
if (this.value != null) {
if ((this.value instanceof Integer) ||
(this.value instanceof Long) ||
(this.value instanceof Double) ||
(this.value instanceof Boolean)) {
json += ", \"value\" : " + this.value.toString();
} else {
json += ", \"value\" : \"" + this.value.toString() + "\"";
}
json += ", \"value\" : " + valueToString(value);
}
json += "}";

Expand Down
62 changes: 58 additions & 4 deletions java/src/main/java/com/outlyer/jmx/jmxquery/JMXQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.outlyer.jmx.jmxquery.object.JMXAttribute;
import com.outlyer.jmx.jmxquery.object.JMXMethod;
/**
*
* JMXQuery is used for local or remote request of JMX attributes
Expand All @@ -28,6 +33,8 @@ public class JMXQuery {
String password = null;
boolean outputJSON = false;

JMXMethod methodInvoke = null;
JMXAttribute setterInvoke = null;
/**
* @param args
*/
Expand All @@ -52,6 +59,33 @@ public static void main(String[] args) throws Exception {

// Process Query
try {
// Set attribute
if (query.setterInvoke != null) {
ObjectName objName = query.connector.queryName(query.setterInvoke.getObjectName());

query.connector.set(objName.getCanonicalName(), query.setterInvoke.getName(),
query.setterInvoke.getTypedValue());
query.connector.disconnect();
return;
}
// Method invoke
if (query.methodInvoke != null) {
ObjectName objName = query.connector.queryName(query.methodInvoke.getObjectName());

Object ret = query.connector.invoke(objName.getCanonicalName(), query.methodInvoke.getName(),
query.methodInvoke.getValues(), query.methodInvoke.getTypes());
if (ret != null) {
if (query.outputJSON) {
System.out.println("{ \"result\": \"" + toString(ret) + "\"}");
} else {
System.out.println(toString(ret));
}
}
query.connector.disconnect();
return;
}

// Read attributes
ArrayList<JMXMetric> outputMetrics = query.connector.getMetrics(query.metrics);
if (query.outputJSON) {
System.out.println("[");
Expand Down Expand Up @@ -105,6 +139,18 @@ public static void main(String[] args) throws Exception {
query.connector.disconnect();
}

private static final String toString(Object obj) {
if (obj instanceof Object[]) {
StringBuilder strBuild = new StringBuilder();
for (Object el : (Object[]) obj) {
strBuild.append(el.toString() + "\n");
}
return strBuild.toString();

}
return obj.toString();
}

/**
* Get key JVM stats. Utility method for quickly grabbing key java metrics
* and also for testing
Expand Down Expand Up @@ -181,15 +227,23 @@ private void parse(String[] args) throws ParseError {
username = args[++i];
} else if (option.equals("-password") || option.equals("-p")) {
password = args[++i];
} else if (option.equals("-query") || option.equals("-q")) {

} else if (option.equals("-query") || option.equals("-q")) {
// Parse query string to break up string in format:
// {mbean}/{attribute}/{key};
String[] query = args[++i].split(";");
for (String metricQuery : query) {
metrics.add(new JMXMetric(metricQuery));
}

} else if (option.equals("-call") || option.equals("-c")) {
ObjectMapper objectMapper = new ObjectMapper();
byte[] decodedBytes = Base64.getDecoder().decode(args[++i]);
String decodedString = new String(decodedBytes);
methodInvoke = objectMapper.readValue(decodedString, JMXMethod.class);
} else if (option.equals("-set") || option.equals("-s")) {
ObjectMapper objectMapper = new ObjectMapper();
byte[] decodedBytes = Base64.getDecoder().decode(args[++i]);
String decodedString = new String(decodedBytes);
setterInvoke = objectMapper.readValue(decodedString, JMXAttribute.class);
} else if (option.equals("-json")) {
outputJSON = true;
} else if (option.equals("-incjvm")) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.outlyer.jmx.jmxquery.object;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
*
* JMXAttribute is used for set the JMX attributes
*
* @author Tibor Kiss
*
*/
public class JMXAttribute extends JMXObject {

private JMXParam value = null;

/**
* get the JMX MBean value
*/
public JMXParam getValue() {
return value;
}

/**
* return the actual value
*/
@JsonIgnore
public Object getTypedValue() {
if(value == null)
return null;
return JMXObjectTypeConverter.toObject(value.getType(), (String)value.getValue());
}

/**
* set the JMX MBean value
*
* @param value
* JMX MBean new value
*/
public void setValue(JMXParam value) {
this.value = value;
}


}
Loading