Search This Blog

Showing posts with label jmx. Show all posts
Showing posts with label jmx. Show all posts

Wednesday, October 9, 2019

How to connect directly to a local JVM via JMX

OpenAF's JMX client enables the creation of JMX "client" scripts. To connect the "client" to the target JVM you need an JMX URL.

But if the JVMs are local to the same host you can request a "special" URL that will connect to them without the need to open any remote JMX ports and change the target Java startup arguments.

To do this first list the "recognized" running JVMs on your host:

> plugin("JMX");
> af.fromJavaMap(jmx.getLocals());
+---------+-----+-------+-----------------------------------+
| Locals: | [0] | name: | /openaf/openaf.jar --console      |
|         |     |   id: | 24720                             |
+---------+-----+-------+-----------------------------------+
|         | [1] | name: | /myApp/myapp.jar                  |
|         |     |   id: | 15004                             |
+---------+-----+-------+-----------------------------------+

Using the id number, for the local Java JVM you want to target, now call attach2Local like this, creating a new JMX object instance:

> var localJMX = new JMX(String(jmx.attach2Local(15004).get("URL")));

If successfull you will now be able to use the localJMX JMX client object:

> var obj = jmx.getObject("java.lang:type=Runtime");
> String(obj.get("ClassPath"));
"/myApp/myapp.jar"

How to access remote JMX data

JMX, the Java Management Extensions, allows you to monitor/manage any Java based process. Since OpenAF is also a Java process it can be used as a "client" to check other java processes (including other OpenAF processes).

To set it up you will need to enable remote JMX access on the target Java process. Typically:

java -D"com.sun.management.jmxremote.port=9999" -D"com.sun.management.jmxremote.authenticate=false" -D"com.sun.management.jmxremote.ssl=false" -jar myApp.jar

Note: is not recommended to disable authentication and SSL if you weren't on a controlled environment.

Now, in OpenAF, you can check remotely some JMX beans like the java.lang.Runtime and java.lang.Memory.

Let's start by creating a JMX object instance:

> plugin("JMX");
> var jmx = new JMX("service:jmx:rmi:///jndi/rmi://127.0.0.1:9999/jmxrmi");

Note: It's also possible to attach directly to running JVMs on the same host without having to change their startup arguments using JMX.attach2Local.

Checking existing attributes

Let's check the available attributes for java.lang.Memory:

> var obj = jmx.getObject("java.lang:type=Runtime");
> af.fromJavaMap(obj.getAttributes());
+-------------+------+----------------+------------------+------------------+
| attributes: |  [0] |      openType: |       className: | java.lang.String |
|             |      |                |     description: | java.lang.String |
|             |      |                |        typeName: | java.lang.String |
+-------------+------+----------------+------------------+------------------+
|             |      | attributeType: | java.lang.String |                  |
|             |      |       isWrite: | false            |                  |
|             |      |        isRead: | true             |                  |
|             |      |            is: | false            |                  |
|             |      |          name: | Name             |                  |
|             |      |   description: | Name             |                  |
+-------------+------+----------------+------------------+------------------+
|             |  [1] |      openType: |       className: | java.lang.String |
|             |      |                |     description: | java.lang.String |
|             |      |                |        typeName: | java.lang.String |
+-------------+------+----------------+------------------+------------------+
|             |      | attributeType: | java.lang.String |                  |
|             |      |       isWrite: | false            |                  |
|             |      |        isRead: | true             |                  |
|             |      |            is: | false            |                  |
|             |      |          name: | ClassPath        |                  |
|             |      |   description: | ClassPath        |                  |
+-------------+------+----------------+------------------+------------------+
...

Retrieving string values

So we now know there are several attributes and their corresponding type: "Name", "ClassPath", etc... To retrieve the current value of each just execute:

> String(obj.get("Name"))
"12345@openaf"
> String(obj.get("ClassPath"))
"/openaf/openaf.jar"

Retrieving composite values

But not all attributes have simple type values like String. If you check java.lang.Memory you will find that the specific values are wrapped on a Java class:

> var obj = jmx.getObject("java.lang:type=Memory");
> af.fromJavaMap(obj.getAttributes()).attributes[1].name
"HeapMemoryUsage"
> af.fromJavaMap(obj.getAttributes()).attributes[1].attributeType
"javax.management.openmbean.CompositeData"
> af.fromJavaMap(obj.getAttributes()).attributes[1].openType.typeName
"java.lang.management.MemoryUsage"

To retrieve composite values just get the first composite value and use the corresponding class methods to retrieve "sub-values":

> Number(o.get("HeapMemoryUsage").get("max"))
1821376512
> Number(o.get("HeapMemoryUsage").get("init"))
130023424
> Number(o.get("HeapMemoryUsage").get("used"))
13376936
> Number(o.get("HeapMemoryUsage").get("committed"))
124780544

Note: The class and type should be available on the OpenAF's classpath if not standard.

Using arrays with parallel

OpenAF is a mix of Javascript and Java, but "pure" javascript isn't "thread-safe" in the Java world. Nevertheless be...