Skip to content

Commit 8fcd43f

Browse files
author
E506806
committed
Extend the JMXQuery library to let the user invoke JMX methods.
This would be very useful to create custom reports, where we can trigger actions as well.
1 parent 01bd76e commit 8fcd43f

13 files changed

Lines changed: 657 additions & 19 deletions

File tree

java/README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Usage
1010
------
1111

1212
```
13-
jmxquery [-url] [-username,u] [-password,p] [-query,q] [-incjvm] [-json] [-help]
13+
jmxquery [-url] [-username,u] [-password,p] [-query,q] [-call,c] [-incjvm] [-json] [-help]
1414
```
1515

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

36+
-call, c
37+
Call a method using a base64 encoded JSON as parameter
38+
JSON format:
39+
{"objectName":"{mBeanName}","name":"{methodName}","params":[{"value":"{value}","type":"{type}"},...]}
40+
Supported types: char, short, int, long, boolean, double, float, String, Float, Double, Short, Int, Long
41+
3642
-incjvm
3743
Will add all standard JVM metrics to the -metrics query if used under java.lang domain
3844
Useful utility function to add JVM metrics quickly and also for testing connections if
@@ -79,6 +85,12 @@ You can get multiple values by joining the mbeans together with semi colons.
7985
java -jar JMXQuery.jar -url service:jmx:rmi:///jndi/rmi://localhost:1616/jmxrmi -q "java.lang:type=ClassLoading/LoadedClassCount;java.lang:type=ClassLoading/UnloadedClassCount"
8086
```
8187

88+
```
89+
Invoke the add method: {"objectName":"com.outlyer.jmx.jmxquery.app.tests:type=Test","name":"add","params":[{"value":"Test ","type":"String"},{"value":"test","type":"String"}]}
90+
91+
java -jar JMXQuery.jar -url service:jmx:rmi:///jndi/rmi://localhost:1616/jmxrmi -c eyJvYmplY3ROYW1lIjoiY29tLm91dGx5ZXIuam14LmpteHF1ZXJ5LmFwcC50ZXN0czp0eXBlPVRlc3QiLCJuYW1lIjoiYWRkIiwicGFyYW1zIjpbeyJ2YWx1ZSI6IlRlc3QgIiwidHlwZSI6IlN0cmluZyJ9LHsidmFsdWUiOiJ0ZXN0IiwidHlwZSI6IlN0cmluZyJ9XX0=
92+
93+
```
8294
Building the Jar
8395
----------------
8496

java/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
<scope>system</scope>
3232
<systemPath>${toolsjar}</systemPath>
3333
</dependency>
34+
<dependency>
35+
<groupId>com.fasterxml.jackson.core</groupId>
36+
<artifactId>jackson-databind</artifactId>
37+
<version>2.9.8</version>
38+
</dependency>
3439
</dependencies>
3540

3641
<build>

java/src/main/java/com/outlyer/jmx/jmxquery/JMXConnector.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
import com.outlyer.jmx.jmxquery.tools.JMXTools;
44
import java.io.IOException;
55
import java.util.ArrayList;
6-
import java.util.Arrays;
76
import java.util.HashMap;
87
import java.util.Iterator;
98
import java.util.Map;
109
import java.util.Set;
1110
import javax.management.InstanceNotFoundException;
1211
import javax.management.IntrospectionException;
1312
import javax.management.MBeanAttributeInfo;
13+
import javax.management.MBeanException;
1414
import javax.management.MBeanInfo;
1515
import javax.management.MBeanServerConnection;
1616
import javax.management.MalformedObjectNameException;
@@ -108,6 +108,48 @@ public void disconnect() throws IOException {
108108
}
109109
}
110110

111+
/**
112+
* invokes a method on the server using JMX
113+
*
114+
* @param name
115+
* - The object name of the MBean on which the method is to be
116+
* invoked.
117+
* @param method
118+
* - The name of the method to be invoked.
119+
* @param args
120+
* - An array containing the arguments of the method to be set
121+
* when the operation is invoked
122+
* @param signatures
123+
* - An array containing the signatures of the arguments, an
124+
* array of class names in the format returned by
125+
* Class.getName().
126+
* @return result of invoking the operation on the MBean specified
127+
* @throws java.io.IOException
128+
* @throws javax.management.MalformedObjectNameException
129+
* @throws javax.management.InstanceNotFoundException
130+
* @throws javax.management.IntrospectionException
131+
* @throws javax.management.ReflectionException
132+
* @throws MBeanException
133+
*/
134+
public Object invoke(String objectName, String method, Object[] args, String[] signatures)
135+
throws IOException, MalformedObjectNameException, InstanceNotFoundException, IntrospectionException,
136+
ReflectionException, MBeanException {
137+
return connection.invoke(new ObjectName(objectName), method, args, signatures);
138+
}
139+
140+
/**
141+
* query the actual name of the MBean
142+
*
143+
* @param name
144+
* - The object search string.
145+
* @return actual name of the MBean
146+
* @throws java.io.IOException
147+
* @throws javax.management.MalformedObjectNameException
148+
*/
149+
public ObjectName queryName(String name) throws MalformedObjectNameException, IOException {
150+
return connection.queryNames(new ObjectName(name), null).iterator().next();
151+
}
152+
111153
/**
112154
* Fetches a list of metrics and their values in one go
113155
*
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package com.outlyer.jmx.jmxquery;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import com.fasterxml.jackson.annotation.JsonIgnore;
9+
10+
/**
11+
*
12+
* JMXMethod is used for local or remote invoke of JMX methods
13+
*
14+
* @author Tibor Kiss
15+
*
16+
*/
17+
public class JMXMethod {
18+
19+
/**
20+
*
21+
* MethodParam is used for pass parameters to a JMXMethod
22+
*
23+
* @author Tibor Kiss
24+
*
25+
*/
26+
public static class MethodParam {
27+
private Object value;
28+
private String type;
29+
30+
/**
31+
* Default constructor
32+
*/
33+
public MethodParam() {
34+
this(null, null);
35+
}
36+
37+
/**
38+
* This constructor is used to create a parameter
39+
*
40+
* @param value
41+
* is the actual value
42+
* @param type
43+
* is a basic type from:
44+
* (String,Double,Float,Short,Integer,Long,Boolean,char,double,float,short,integer,long,
45+
* boolean)
46+
*/
47+
public MethodParam(Object value, String type) {
48+
setValue(value);
49+
setType(type);
50+
}
51+
52+
/**
53+
* returns the parameter value
54+
*
55+
* @return parameter value
56+
*/
57+
public Object getValue() {
58+
return value;
59+
}
60+
61+
/**
62+
* set the parameters value
63+
*
64+
* @param value
65+
* parameters value
66+
*/
67+
public void setValue(Object value) {
68+
this.value = value;
69+
}
70+
71+
public String getType() {
72+
return type;
73+
}
74+
75+
public void setType(String type) {
76+
this.type = type;
77+
}
78+
}
79+
80+
private static final Map<String, String> typeMap = new HashMap<String, String>();
81+
static {
82+
typeMap.put("String", String.class.getName());
83+
typeMap.put("Double", Double.class.getName());
84+
typeMap.put("Float", Float.class.getName());
85+
typeMap.put("Short", Short.class.getName());
86+
typeMap.put("Integer", Integer.class.getName());
87+
typeMap.put("Long", Long.class.getName());
88+
typeMap.put("Boolean", Boolean.class.getName());
89+
90+
typeMap.put("char", char.class.getName());
91+
typeMap.put("short", short.class.getName());
92+
typeMap.put("int", int.class.getName());
93+
typeMap.put("long", long.class.getName());
94+
typeMap.put("double", double.class.getName());
95+
typeMap.put("float", float.class.getName());
96+
typeMap.put("boolean", boolean.class.getName());
97+
typeMap.put("double", double.class.getName());
98+
99+
}
100+
101+
private final static Object toObject(final String typeName, final String value) {
102+
if (Boolean.class.getName().endsWith(typeName))
103+
return Boolean.parseBoolean(value);
104+
if (Byte.class.getName().endsWith(typeName))
105+
return Byte.parseByte(value);
106+
if (Short.class.getName().endsWith(typeName))
107+
return Short.parseShort(value);
108+
if (Integer.class.getName().endsWith(typeName))
109+
return Integer.parseInt(value);
110+
if (Long.class.getName().endsWith(typeName))
111+
return Long.parseLong(value);
112+
if (Float.class.getName().endsWith(typeName))
113+
return Float.parseFloat(value);
114+
if (Double.class.getName().endsWith(typeName))
115+
return Double.parseDouble(value);
116+
117+
return value;
118+
}
119+
120+
private String objectName;
121+
private String name;
122+
123+
private final List<MethodParam> params = new ArrayList<MethodParam>();
124+
125+
/**
126+
* return the JMX MBean name
127+
*
128+
* @return JMX MBean name
129+
*/
130+
public String getObjectName() {
131+
return objectName;
132+
}
133+
134+
/**
135+
* Set the JMX MBean name
136+
*
137+
* @param objectName
138+
* JMX MBean name
139+
*/
140+
public void setObjectName(String objectName) {
141+
this.objectName = objectName;
142+
}
143+
144+
/**
145+
* return the name of the JMX method
146+
*
147+
* @return name of the JMX method
148+
*/
149+
public String getName() {
150+
return name;
151+
}
152+
153+
/**
154+
* set the name of the JMX method
155+
*
156+
* @param name
157+
* name of the JMX method
158+
*/
159+
public void setName(String name) {
160+
this.name = name;
161+
}
162+
163+
/**
164+
* return the list of parameters
165+
*
166+
* @return list of parameters
167+
*/
168+
public List<MethodParam> getParams() {
169+
return params;
170+
}
171+
172+
/**
173+
* This method can be used to add a parameter to a method
174+
*
175+
* @param value
176+
* @param type
177+
*/
178+
public void addParam(Object value, String type) {
179+
params.add(new MethodParam(value, type));
180+
}
181+
182+
/**
183+
* This method returns the values as an array
184+
*
185+
* @return array of value
186+
*/
187+
@JsonIgnore
188+
public Object[] getValues() {
189+
List<Object> result = new ArrayList<Object>();
190+
for (MethodParam par : params) {
191+
result.add(toObject(typeMap.get(par.getType()), par.getValue().toString()));
192+
}
193+
return result.toArray(new Object[result.size()]);
194+
}
195+
196+
/**
197+
* This method returns the values types as an array
198+
*
199+
* @return array of the type of values
200+
*/
201+
@JsonIgnore
202+
public String[] getTypes() {
203+
List<String> result = new ArrayList<String>();
204+
for (MethodParam par : params) {
205+
result.add(typeMap.get(par.getType()));
206+
}
207+
return result.toArray(new String[result.size()]);
208+
}
209+
210+
}

java/src/main/java/com/outlyer/jmx/jmxquery/JMXMetric.java

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,42 @@ public String toString() {
289289
s += " (" + attributeType + ")";
290290
}
291291
if (value != null) {
292-
s += " = " + value.toString();
292+
if (value instanceof String) {
293+
s += " = " + value.toString();
294+
} else {
295+
s += " = " + valueToString(value);
296+
}
293297
}
294298

295299
return s;
296300
}
301+
302+
private static String valueToString(Object value) {
303+
if (value == null) {
304+
return "null";
305+
}
306+
if (value.getClass().isArray()) {
307+
return arrayToString((Object[]) value);
308+
}
309+
if ((value instanceof Integer) || (value instanceof Long) || (value instanceof Double)
310+
|| (value instanceof Boolean)) {
311+
return value.toString();
312+
}
313+
return new StringBuilder().append("\"").append(value).append("\"").toString();
314+
}
315+
316+
private static String arrayToString(Object[] array) {
317+
String s = "[";
318+
boolean separatorRequired = false;
319+
for (Object v : array) {
320+
if (separatorRequired)
321+
s += ",";
322+
separatorRequired = true;
323+
s += valueToString(v);
324+
}
325+
s += "]";
326+
return s;
327+
}
297328

298329
/**
299330
* Returns JSON representation of metric
@@ -326,14 +357,7 @@ public String toJSON() {
326357
json += ", \"attributeType\" : \"" + this.attributeType + "\"";
327358
}
328359
if (this.value != null) {
329-
if ((this.value instanceof Integer) ||
330-
(this.value instanceof Long) ||
331-
(this.value instanceof Double) ||
332-
(this.value instanceof Boolean)) {
333-
json += ", \"value\" : " + this.value.toString();
334-
} else {
335-
json += ", \"value\" : \"" + this.value.toString() + "\"";
336-
}
360+
json += ", \"value\" : " + valueToString(value);
337361
}
338362
json += "}";
339363

0 commit comments

Comments
 (0)