////
  Copyright 2009-2023 Roland Huss

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
////
[#read]
=== Reading attributes (read)

Reading MBean attributes is probably the most used JMX method,
especially when it comes to monitoring. Concerning Jolokia, it is
also the most powerful one with the richest semantics. Obviously
the value of a single attribute can be fetched, but Jolokia
supports also fetching of a list of given attributes on a single
MBean or even on multiple MBeans matching a certain pattern.

Reading attributes are supported by both kinds of requests,
`GET` and `POST`.

NOTE: Don't confuse fetching multiple attributes on possibly multiple
MBeans with bulk requests. A single read request will always
result in a single read response, even when multiple attribute
values are fetched. Only the single response's structure of the
`value` will differ depending on what kind of
read request was performed.

A read request for multiple attributes on the same MBean is
initiated by giving a list of attributes to the request. For a
POST request this is an JSON array, for a GET request it is a
comma separated list of attribute names (where slashes and
exclamation marks must be escaped as described in
xref:jolokia_protocol.adoc#escape-rules[Escaping rules]). If no attribute is provided, then all
attributes are fetched. The MBean name can be given as a pattern
in which case the attributes are read on all matching MBeans. If a
MBean pattern and multiple attributes are requested, then only the
value of attributes which matches both are returned, the others
are ignored.

Paths can be used with pattern and multiple attribute read as well. In order to
skip the extra value levels introduced by a pattern read, the wildcard
`pass:[*]` can be used. For example, a read request for the MBean Pattern
`pass:[java.lang:type=GarbageCollector,*]` for the Attribute `LastGcInfo`
returns a complex structure holding information about the last garbage collection. If one is
looking only for the used memory during garbage collection, a path `used` could be used if
this request wouldn't be a pattern request (i.e. refers a specific, single MBean).
But in this case since a
nested map with MBean and Attribute names is returned, the path `pass:[*/*/*/*/used]` has to be used
in order to skip the extra levels (for different heaps/spaces) for applying the path.
Note that in the following example the final value is _not_ the full GC-Info but only the
value of its `used` entry for different spaces:

[,json]
----
"value": {
  "java.lang:name=G1 Young Generation,type=GarbageCollector": {
    "LastGcInfo": {
      "duration": 3,
      "memoryUsageBeforeGc": {
        "CodeHeap 'profiled nmethods'": 4780288,
        "G1 Old Gen": 4934656,
        "CodeHeap 'non-profiled nmethods'": 928256,
        "G1 Survivor Space": 4194304,
        "Compressed Class Space": 1331528,
        "Metaspace": 12812816,
        "G1 Eden Space": 20971520,
        "CodeHeap 'non-nmethods'": 1271296
      },
      "GcThreadCount": 5,
      "startTime": 786,
      "endTime": 789,
      "id": 2,
      "memoryUsageAfterGc": {
        "CodeHeap 'profiled nmethods'": 4780288,
        "G1 Old Gen": 9082880,
        "CodeHeap 'non-profiled nmethods'": 928256,
        "G1 Survivor Space": 2597960,
        "Compressed Class Space": 1331528,
        "Metaspace": 12812816,
        "G1 Eden Space": 0,
        "CodeHeap 'non-nmethods'": 1271296
      }
    }
  }
}
----

The following rule of thumb applies:

* If a wildcard is used, everything at that point in the path is
matched. The next path parts are used to match from there
on. All the values on this level are included.
* Every other path part is literally compared against the values
on that level. If there is a match, this value is
_removed_ in the answer so that at the end
you get back a structure with the values on the wildcard levels
and the leaves of the matched parts.
* If used with wildcards, paths behave also like
filters. E.g. you can use a path `pass:[*/*/*/*/used]` on
the MBean pattern `java.lang:*` and get back
only that portions which contains "used" as key, all others are
ignored.

[#get-read]
==== GET read request

The GET URL for a read request has the following format:

----
<base-url>/read/<mbean name>/<attribute name>/<inner path>
----

.GET Read Request
[cols="15,~,30"]
|===
|Part|Description|Example

|`<mbean name>`
|The
https://docs.oracle.com/en/java/javase/11/docs/api/java.management/javax/management/ObjectName.html[ObjectName,role=externalLink,window=_blank]
of the MBean for which the attribute should be fetched. It
contains two parts: A domain part and a list of properties
which are separated by `:`. Properties
themselves are combined in a comma separated list of
key-value pairs. This name can be a pattern in which case
multiple MBeans are queried for the attribute value.
|`java.lang:type=Memory`

|`<attribute name>`
|Name of attribute to read. This can be a list of Attribute
names separated by comma. According to URI compliance, some special characters need to be
escaped as described in
xref:jolokia_protocol.adoc#escape-rules[Escaping rules]. If no attribute is given, all
attributes are read.
|`HeapMemoryUsage`

|`<inner path>`
|This optional part describes an _inner
path_ as described in xref:jolokia_protocol.adoc#paths[Paths]
|`used`
|===

With this URL the used heap memory can be obtained:
----
http://localhost:8080/jolokia/read/java.lang:type=Memory/HeapMemoryUsage/used
----

[#post-read]
==== POST read request

A the keys available for read POST requests are shown in the
following table.

.POST Read Request
[cols="15,~,30"]
|===
|Key|Description|Example

|`type`
|*`read`*
|

|`mbean`
|MBean's ObjectName which can be a pattern
|`java.lang:type=Memory`

|`attribute`
|Attribute name to read or a JSON array containing a list
of attributes to read. No attribute is given, then all attributes
are read.
a|`HeapMemoryUsage`

`[ "HeapMemoryUsage", "NonHeapMemoryUsage" ]`

|`path`
|Inner path for accessing the value of a complex value
(xref:jolokia_protocol.adoc#paths[Paths])
|`used`
|===

The following request fetches the number of active threads:
[,json]
----
{
  "type": "read",
  "mbean": "java.lang:type=Threading",
  "attribute": "ThreadCount"
}
----

[#response-read]
==== Read response

The general format of the JSON response is described in
xref:jolokia_protocol.adoc#responses[Responses] in detail.  A typical response for an
attribute read operation for a GET request with URL like:

----
http://localhost:8080/jolokia/read/java.lang:type=Memory/HeapMemoryUsage
----

[,json]
----
{
  "request": {
    "mbean": "java.lang:type=Memory",
    "attribute": "HeapMemoryUsage",
    "type": "read"
  },
  "history": [
    {
      "value": {
        "init": 524288000,
        "committed": 532676608,
        "max": 8334082048,
        "used": 78027104
      },
      "timestamp": 1702454713
    },
    ...
  ],
  "value": {
    "init": 524288000,
    "committed": 532676608,
    "max": 8334082048,
    "used": 86415712
  },
  "status": 200,
  "timestamp": 1702454822
}
----

NOTE:: Since Jolokia 2.1.0 we can use `includeRequest` parameter to tell Jolokia to exclude `request` field from the response.

The `value` contains the response's
value. For simple data types it is a scalar value, more complex
types are serialized into a JSON object. See
xref:jolokia_protocol.adoc#serialization[Object serialization] for detail on object serialization.

For a read request of a single MBean with multiple attributes, the
returned value is a JSON object with the attribute names as keys
and their values as values. For example a request to
`http://localhost:8080/jolokia/read/java.lang:type=Memory`
leads to

[,json]
----
{
  "request": {
    "mbean": "java.lang:type=Memory",
    "type": "read"
  },
  "value": {
    "ObjectPendingFinalizationCount": 0,
    "Verbose": false,
    "HeapMemoryUsage": {
      "init": 524288000,
      "committed": 532676608,
      "max": 8334082048,
      "used": 94804320
    },
    "NonHeapMemoryUsage": {
      "init": 7667712,
      "committed": 38928384,
      "max": -1,
      "used": 36905512
    },
    "ObjectName": {
      "objectName": "java.lang:type=Memory"
    }
  },
  "status": 200,
  "timestamp": 1702454894
}
----

A request to a MBean pattern returns as value a JSON object,
with the MBean names as keys and as value another JSON object
with the attribute name as keys and the attribute values as
values. For example a request
`http://localhost:8080/jolokia/read/java.lang:type=*/HeapMemoryUsage`
returns something like

[,json]
----
{
  "request": {
    "mbean": "java.lang:type=*",
    "attribute": "HeapMemoryUsage",
    "type": "read"
  },
  "value": {
    "java.lang:type=Memory": {
      "HeapMemoryUsage": {
        "init": 524288000,
        "committed": 532676608,
        "max": 8334082048,
        "used": 103192928
      }
    }
  },
  "status": 200,
  "timestamp": 1702454978
}
----
