////
  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.
////
[#client-javascript]
== JavaScript Client Library

NOTE: Documentation for the previous version (pre-NPM, not based on TypeScript) of JavaScript library is available here: xref:client/javascript-old.adoc[JavaScript Client Library (before ES modules)].

Notable difference from previous version (pre 2.1.0) are:

* The code is developed now using TypeScript language and processed using https://rollupjs.org/[Rollup JS] into ESM version (`jolokia.mjs` to be used with `import` statement) and UMD version (`jolokia.js` - to be used with browsers when not loading the script as `type="module"`)
* There's no dependency on https://jquery.com/[JQuery] anymore
* For HTTP requests, we use https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API[Fetch API].
* There's no support for ancient https://en.wikipedia.org/wiki/JSONP[JSONP]. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS[CORS] it the way to handle cross-origin requests.
* Because Fetch API is used, there's no direct support for _synchronous requests_ - this can be achieved simply using `async` and `await`
* There was an `ajaxError` option to handle HTTP/connection errors, but it was used to configure jQuery's `$.ajax` call. Now `Jolokia.request` in Promise mode returns a `Promise` object and we can handle _global errors_ using `Promise.catch()` handler where the passed object is a https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object.
* In callback mode we can still pass `success` and `error` callbacks (to handle successfull and failed Jolokia responses - all delivered with HTTP 200 status code) and additionally we can pass `fetchError` (name was changed from `ajaxError`, because signature has changed as well) configuration option when creating new `Jolokia` object - this callback will be called with https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object to check for HTTP errors, etc. (when HTTP status is not `200`) and/or with an error thrown by `fetch()` API call.
* https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#exceptions[`fetch()` call] may throw an exception (`DOMException` or `TypeError`) when networking error occurs or `fetch()` is configured in wrong way (for example with bad headers). Mind that it was a bit different with jQuery Ajax, where both HTTP error responses (like `404`) and networking errors where handled with single callback being called with `xhr` instance. After switching to `fetch()` API, these errors in promise mode have to be handled in different way:
** networking and configuration errors can be handled by attaching a `.catch()` handler to `Jololokia.request()` returned promise. The error will be a `DOMException` or `TypeError`
** HTTP error responses (where status is different than `200`) can be handled by attaching a `.catch()` handler, where the passed object will be a https://developer.mozilla.org/en-US/docs/Web/API/Response[Response].
** In callback mode, both the exception and failed `Response` objects can be passed to a callback configured with `fetchError` option.

All methods of this library are available via the
`Jolokia` client object, which needs to be
instantiated up-front. In the following example a client object is
created and the used heap memory is requested synchronously via
the simple API. The agent is deployed within the same web archive
which also serves this script.

Here's a sample code fragment that uses global `Jolokia` class which is used to create a `jolokia`
instance used to invoke simple (from `@jolokia.js/simple` package) `getAttribute()` operation:

[,javascript]
----
const jolokia = new Jolokia("/jolokia")
const value = await jolokia.getAttribute("java.lang:type=Memory", "HeapMemoryUsage", "used")
console.log("Heap Memory used: " + value)
----

[#js-installation]
=== Installation

The Jolokia JavaScript library is distributed in the form of npm packages which should be used as standard JavaScript libraries. It's out of scope of this documentation to describe all possible bundler setups which may be used, let's simply focus on two _flavors_ of these libraries.

`package.json` for `jolokia.js` package contains this module-related section:

[,json]
----
"exports": {
  ".": {
    "types": "./dist/dts/jolokia.d.ts",
    "import": "./dist/jolokia.mjs",
    "default": "./src/jolokia.ts"
  }
}
----

The recommended way to use this package is with JavaScript ES modules:

[,javascript]
----
import Jolokia from "jolokia.js"

const jolokia = new Jolokia("/jolokia")
...
----

However if there's a need to use Jolokia JavaScript libraries directly, it's always possible
to download relevant files (normal an minified) from link:/download.html[download page].
Then we can refer to the scripts from HTML page:

[,html,subs="attributes,verbatim"]
----
<head>
  <script src="jolokia-{jolokia-version}.min.js"></script>
  <script src="jolokia-simple-{jolokia-version}.min.js"></script>
</head>
----

A Jolokia client is always created as an instance of
`Jolokia`. Requests to the agent are sent
by calling methods on this object. The constructing function
takes a plain object, which provides default parameters which
are used in the `request()` if no
overriding are given there.

[#js-request]
=== Usage

All functions of this library are available as methods of the
`Jolokia` object. The `options` argument needs to be
instantiated as usual and it takes a set of default options, which
can be overwritten by subsequent requests. On the most basic
layer is a single `request()` method,
which takes two arguments: A request object and an optional
options object. For example, a request for obtaining
the agent's version for a agent running on the same server which
delivered the JavaScript looks like:

[,javascript]
----
let jolokia = new Jolokia({ url: "/jolokia" });
let response = await jolokia.request({ "type": "version" }, { "method": "post" });
console.log("Agent Version: " + response.value.agent);
----

If the constructor is used with a single string argument, this
value is considered to be the agent's access URL. I.e. in the
example above the construction of the
`Jolokia` could have been performed with a
single string argument (`new Jolokia("/jolokia")`).

[#js-request-format]
==== Requests

Jolokia requests and responses are represented as JSON
objects. They have exactly the same format, which is expected
and returned by the agent as defined in
xref:jolokia_protocol.adoc[] for POST requests. All request types are
supported.

The `request()` method expects as its first
argument either a single request object or, for bulk requests,
an array of request objects.

When Jolokia JavaScript library was using JQuery Ajax, there were two types of operations supported:

* synchronous - when `options` object didn't contain `success` callback
* asynchronous - when user specified `success` callback in `options` object

Depending on this for synchronous
operations either a single response JSON object is returned or
an array of responses (in the order of the initial request
array). For asynchronous request one or more callbacks are
called for each response separately. See
<<js-request-sync-async>> for details.

With new Fetch API, there are more types of operations:

* _callback mode_ for compatibility purposes - you have to pass `success` and (optional) `error` callbacks through `options` object
* _recommended_ JSON method in _promise mode_ when there's no `success` callback passed and `request()` returns a Promise object:
** for HTTP status 200, it is resolved with the response value, which may be successfull or error Jolokia responses containing JSON data with response or error details obtained from `Response.json()`
** for HTTP status != 200, it throws an exception which is a Fetch `Response` object - user can attach `.catch()` to the promise and analyze the https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object for headers, status code, etc.
* _special_ Text method in _promise mode_ when there's no `success` callback, `dataType: "text"` is passed and `request()` returns a Promise object:
** for HTTP status 200, it is resolved with the response value, which is plain text response obtained from `Response.text()`.
** for HTTP status != 200 it's the same as in _recommended_ JSON method
* _low level_ Response method in _promise mode_, when `resolve: "response"` is passed with `options` and `request()` returns a Promise object:
** for any HTTP status code, the returned promise is resolved with entire https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object and user is free to call `Response.json()`, `Response.text()`, `Response.blob()` or any method from https://developer.mozilla.org/en-US/docs/Web/API/Response[Response API].

Remember - when no `success` callback is passed, the returned Promise has to be configured for resolution:

* by attaching `.then()` to get the value (both successful and error Jolokia responses - all within successful HTTP response (status == `200`))
* by attaching `.catch()` to catch the exceptions:
** a https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object when there is some HTTP response
** a `DOMException` or `TypeError` when there's a networking or configuration error (see https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#exceptions[fetch exceptions])
* by using `await jolokia.request()` to get the response
* by surrounding with `try..catch` when there's no `.catch()` used

For convenience, in both _callback_ and _promise_ modes, we can pass `fetchError` callback method in the options (in `request()` call or initially when creating `Jolokia` instance). Before Jolokia 2.1.0 this option was passed directly to `$.ajax()` call in jQuery. This callback has the following signature:

[,javascript]
----
function(response, error)
----

and the parameters are:

* `response` is a https://developer.mozilla.org/en-US/docs/Web/API/Response[Response] object when available
* `error` is an exception object thrown by `fetch()` call (see https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#exceptions[fetch exceptions])

The following example shows a single and bulk request call to
the Jolokia agent:

[,javascript]
----
let jolokia = new Jolokia({ "url": "/jolokia" })
let req1 = { "type": "read", "mbean": "java.lang:type=Memory", "attribute": "HeapMemoryUsage" }
let req2 = { "type": "list" }
let response = await jolokia.request(req1)
let responses = await jolokia.request([ req1, req2 ])
----

[#js-request-options]
==== Request options

Each request can be configured with a set of optional parameters
provided either as default during construction of the
`Jolokia` object or as optional last
parameter for the request object. Also a request can carry a
`config` attribute, which can be used for all
processing parameters (xref:jolokia_protocol.adoc#processing-parameters[Processing parameters]).
The known options are summarized in <<js-request-options-table>>

[#js-request-options-table]
.Request options
[cols="20,~"]
|===
|Key|Description

|`url`
|Agent URL (mandatory)

|`method`
|Either "post" or "get" depending on the desired HTTP method
(case does not matter).  Please note, that bulk requests are
not possible with "get". On the other hand, JSONP requests
are not possible with "post" (which obviously implies that
bulk request cannot be used with JSONP requests). Also, when
using a `read` type request for multiple
attributes, this also can only be sent as "post"
requests. If not given, a HTTP method is determined
dynamically. If a method is selected which doesn't fit to the
request, an error is raised.

|`dataType`
|The type of data specified to Jolokia request. The default value is `json`,
and the response is parsed as JSON to an object. If the value is `text`,
the response is returned as plain text without parsing. The client is then
responsible for parsing the response. This can be useful when a custom JSON
parsing is necessary. The value is returned as Promise's resolution value. +
Jolokia Simple API (jolokia-simple.js) doesn't support `text` as dataType. +
*Added since jolokia.js 2.0.2*

|`success`
|Callback function which is called for a successful
request. The callback receives the response as single
argument. If no `success` callback is given, then
the request returns a Promise.

|`error`
|Callback in case a Jolokia error occurs. A Jolokia error is
one, in which the HTTP request succeeded with a status code
of 200, but the response object contains a Jolokia (not HTTP) status other than
OK (200) which happens if the request JMX operation
fails. This callback receives the full Jolokia response
object (with a key `error` set). If no error
callback is given, but `success` is available, the error response is printed to the JavaScript
console by default.

|`fetchError`
|A callback invoked when `fetch()` returns a `Response` object with HTTP status different than 200 or simply https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch#exceptions[throws an exception].

This callback can be specified both in _callback_ and _promise_ mode - both at `request()` time and `Jolokia` instantiation time.

|`credentials`
|This option is passed directly to `fetch()` call. See https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#headers[headers option].

|`username`
|A username used for HTTP authentication

|`password`
|A password used for HTTP authentication

|`timeout`
|Timeout for the HTTP request used with https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static[Abort Signal]

|`headers`
| This option is passed directly to `fetch()` call. 

|`maxDepth`
|Maximum traversal depth for serialization of complex return values

|`maxCollectionSize`
|Maximum size of collections returned during serialization.
If larger, the collection is returned truncated.

|`maxObjects`
|Maximum number of objects contained in the response.

|`serializeLong`
|How to serialize long values in the JSON response: `number` or `string`.
The default `number` simply serializes longs as numbers in JSON.
If set to `string`, longs are serialized as strings.
It can be useful when a JavaScript client consumes the JSON response,
because numbers greater than the max safe integer don't retain their precision
in JavaScript. +
*Added since Jolokia 2.0.3*

|`ignoreErrors`
|If set to "true", errors during JMX operations and JSON
serialization are ignored. Otherwise if a single
deserialization fails, the whole request returns with an
error. This works only for certain operations like pattern
reads.

|`canonicalNaming`
|Defaults to false for initiali property lists on object names; if set to "true" then canonical (sorted) order of properties will be used.

|`includeRequest`
|Whether the response object should contain related request object. +
This option may be configured globally and overridden at request time.
When `false`, bulk responses have to be correlated with requests by matching
the requests using index number - responses come in the same order as requests. +
*Added since Jolokia 2.1.0*

|`listKeys`
|Whether the response object for `list()` operation should contain `keys` field
that lists all the keys obtained from each `javax.management.ObjectName` of the response.
This may save you time parsing the name yourself. +
*Added since Jolokia 2.1.0*

|`listCache`
|A flag (defaults to `false`) to enable _optimized list response_. +
With this flag enabled, `list()` operation returns a bit different structure (that's why we've upgraded protocol version to `8.0`) where some MBeans may _point to_ cached, shared MBeanInfo JSON fragment. This heavily decreases the size of `list()` response. +
*Added since Jolokia 2.1.0*

|`serializeException`
|If true then in case of an error, the exception itself is returned in
it JSON representation under the key `error_value`
in the response object.

|`includeStackTrace`
|By default, a stacktrace is returned with every error (key: `stacktrace`)
This can be omitted by setting the value of this option to `false`.

|`ifModifiedSince`
|The `LIST` operations provides an
optimization in that it remembers, when the set of
registered MBeans has been changes last. If a timestamp
(in epoch seconds) is provided with this parameter, then
the LIST operation returns an empty response
(i.e. `value` is null) and a
`status` code of 304 (Not Modified) if
the MBeans haven't changed. If you use the request
scheduler (<<js-request-options-table>>)
then this feature can be used to get the callbacks called
only if a value is returned. For the normal request, the
error callback is called which must check the status itself.
|===

[#js-request-sync-async]
==== Operational modes

Requests can be handled either with Promises or callbacks.
If a `success` callback is given in the
request options, the `fetch()` promise is handled by Jolokia.
The callback gets these arguments:

* a Jolokia JSON
response object (see xref:jolokia_protocol.adoc#request-response[Requests and Responses])
* an integer index indicating for which response this callback is being
called.

For bulk requests, this index corresponds to the array
index of the request which lead to this response. The value of
this option can be an array of callback functions which are
called in a round robin fashion when multiple responses are
received in case of bulk requests. These callbacks are called
only when the returned Jolokia response has a status code of
`200`, otherwise the callback(s) given with
the `error` option are consulted. If no error
callback is given, the error is printed on the console by
default. As for success callbacks, error callbacks receive the
Jolokia error response as a JSON object.

The following example shows callback-based requests for a single
Jolokia request as well as for bulk request with multiple
callbacks.

[,javascript]
----
let jolokia = new Jolokia("/jolokia");

// Single request with a single success callback
jolokia.request(
  {
    "type": "read",
    "mbean": "java.lang:type=Memory",
    "attribute": "HeapMemoryUsage"
  },
  {
    "success": function(response) {
      if (response.value.used / response.value.max > 0.9) {
        console.info("90% of heap memory exceeded");
      }
    },
    "error": function(response) {
      console.info("Jolokia request failed: " + response.error);
    }
  }
);

// Bulk request with multiple callbacks
jolokia.request(
  [
    {
      "type": "read",
      "mbean": "java.lang:type=Threading",
      "attribute": "ThreadCount"
    },
    {
      "type": "read",
      "mbean": "java.lang:type=Runtime",
      "attribute": [ "VmName", "VmVendor" ]
    }
  ],
  {
    "success": [
      function(response) {
        console.log("Number of threads: " + response.value);
      },
      function(response) {
        console.log("JVM: " + response.value.VmName + " -- " + response.value.VmVendor);
      }
    ],
    "error": function(response) {
      alert("Jolokia request failed: " + response.error);
    }
  }
);
----

Both callbacks, `success` and
`error`, are only called when HTTP response code is `200`.
In case of an error on the HTTP level It is the responsibility of user
to _attach_ `.catch()` to the returned Promise object. The passed function is called with the
https://developer.mozilla.org/en-US/docs/Web/API/Response[`Response`] object, so we can get more information. For example:

[,javascript]
----
const response = await jolokia.request({ type: "version" })
  .catch(r => {
      if (r.status <= 400) {
        // handle non-critical error
        console.warn(r.statusText)
      } else {
        // handle codes like 404 or 500
        console.warn("Critical error", r.statusText)
      }
  })
----

As explained in xref:jolokia_protocol.adoc#request-response[Requests and Responses] the Jolokia
agent supports two HTTP methods, `GET` and
`POST`. `POST` is more
powerful since it supports more features. e.g. bulk requests and
JMX proxy requests are only possible with POST. By default, the
Jolokia JavaScript library selects an HTTP method automatically,
which is `GET` for simple cases and `POST`
for more sophisticated requests. The HTTP method can be
overridden by setting the option `method` to
`"get"` or `"post"`.

There are some limitations in choosing the HTTP method depending
on the request and other options given:

* Bulk requests (i.e. an array of multiple requests) can only be
used with `POST`.
* `READ` requests for multiple attributes
(i.e. the `attribute` request parameter is
an array of string values) can only be used with
`POST`.
* The JMX proxy mode (see xref:proxy_mode.adoc[]) can only be used
with `POST`.

=== Using Promises

Without callbacks we can leverage full potential of promises.

The example we've shown to describe `success` and `error` callbacks can be written using promises:

[,javascript]
----
let jolokia = new Jolokia("/jolokia");

// Single request with a single success callback
let response = await jolokia.request({
    "type": "read",
    "mbean": "java.lang:type=Memory",
    "attribute": "HeapMemoryUsage"
  }).catch(r => {
      console.info("Jolokia request failed: " + r.statusText);
  })
if (response && response.value.used / response.value.max > 0.9) {
    console.info("90% of heap memory exceeded")
}
----

[#js-simple]
=== Simple API

Building upon the basic
`Jolokia.request()` method, a simplified
access API is available. It is contained in
`jolokia-simple.js` (from `@jolokia.js/simple` npm package) which must be included after
`jolokia.js`. This API provides dedicated
method for the various request types and supports all options as
described in <<js-request-options-table>>.

There is one notable difference for asynchronous callbacks and
synchronous return values though: In case of a successful call,
the callback is fed with the response's
`value` object, not the full response
(i.e. `response.value` instead of `response`).
Similar when a `Promise` is returned, it is resolved with
the value itself from the response and not entire response.

There are also differences in error handling between _simple_ and _normal_ API:

* for callback mode, the Jolokia error message is passed in the same way
* for promise mode, if HTTP return code is 200, but it is a Jolokia error, instead of returning
the error JSON message, its `error` field is thrown as an exception. HTTP error codes different that 200 are handled in the same way (by throwing or returning Fetch Response object)

Remember - to deal with values directly, `await` has to be used on the Promise returned from simple API.

`getAttribute(mbean, attribute, path, opts)`:: This method returns the value of an JMX attribute
`attribute` of an MBean `mbean`. A path
can be optionally given, and the optional request options are
given as last argument(s). The return value for synchronous
operations are the attribute's value, for callback
operations (i.e. `opts.success != null`) it is
`null`. See xref:protocol/read.adoc[Reading attributes (read)] for
details.
+
For example, the following method call can be used
to synchronously fetch the current heap memory usage:
+
[,javascript]
----
let memoryUsed = await jolokia.getAttribute("java.lang:type=Memory", "HeapMemoryUsage", "used");
----

`setAttribute(mbean, attribute, value, path, opts)`:: For setting an JMX attribute, this method takes the MBean's
name `mbean`, the attribute
`attribute` and the value to set as
`value`. The optional `path` is the
_inner path_ of the attribute on which
to set the value (see xref:protocol/write.adoc[Writing attributes (write)] for
details). The old value of the attribute is returned or
given to a `success` callback.
+
To enable verbose mode in the memory-handling beans, use
+
[,javascript]
----
let gsLoggingWasOn = await jolokia.setAttribute("java.lang:type=Memory", "Verbose", true);
----

`execute(mbean, operation, arg1, arg2, ..., opts)`:: With this method, a JMX operation can be executed on the
MBean `mbean`. Beside the operation's name
`operation`, one or more arguments can be given
depending on the signature of the JMX operation. The
return value is the return value of the operation. See
xref:protocol/exec.adoc[Executing JMX operations (exec)] for details.
+
The following exampled asynchronously fetches a thread dump
as a JSON object and logs it into the console:
+
[,javascript]
----
jolokia.execute("java.lang:type=Threading", "dumpAllThreads(boolean,boolean)", true, true, {
  "success": function(value) {
    console.log(JSON.stringify(value));
  }
});
----

`search(mBeanPattern, opts)`:: Searches for one or more MBeans whose object names fit the
pattern `mBeanPattern`. The return value is a list
of strings with the matching MBean names or `null`
if none is found. See xref:protocol/search.adoc[Searching MBeans (search)] for details.
+
The following example looks up all application servers
available in all domains:
+
[,javascript]
----
let servletNames = await jolokia.search("*:j2eeType=Servlet,*");
----

`list(path, opts)`:: For getting meta information about registered MBeans,
the `list` command can be used. The
optional `path` points into this meta
information for retrieving partial information. The format
of the return value is described in detail in
xref:protocol/list.adoc[Listing MBeans (list)].
+
This example fetches only the meta information for the
attributes of the
`java.lang:type=OperatingSystem` MBean:
+
[,javascript]
----
let attributesMeta = await jolokia.list("java.lang/type=OperatingSystem/attr");
----

`version(opts)`:: The `version` method returns the
agent's version, the protocol version, and possibly some
additional server-specific information. See
xref:protocol/version.adoc[Getting the agent version (version)] for more information about this
method.
+
A sample return value for an Apache Tomcat server looks like:
+
[,json,subs="attributes,verbatim"]
----
{
  "agent": "{jolokia-version}",
  "protocol": "8.0",
  "details": {
    "agent_version": "2.1.0-SNAPSHOT",
    "agent_id": "192.168.0.221-72527-6baa8838-servlet",
    "server_product": "tomcat",
    "server_vendor": "Apache",
    "server_version": "10.1.28",
    "secured": true,
    "url": "http://192.168.0.221:8080/jolokia"
  },
  "id": "192.168.0.221-72527-6baa8838-servlet",
  "config": {
    ...
  },
  "info": {
    "proxy": {},
    "jmx": {}
  }
}
----

[#js-poller]
=== Request scheduler

A `Jolokia` object can be also used for
periodically sending requests to the agent. Therefore requests
can be registered to the client object, and a poller can be
started and stopped. All registered requests are send at once
with a single bulk request so this is a quite efficient method for
periodically polling multiple values.

Here is a simple example, which queries the heap memory usage
every 10 seconds and prints out the used memory on the console:

[,javascript]
----
let jolokia = new Jolokia("/jolokia")
handle = jolokia.register(function(resp) {
  console.log("HeapMemory used: " + resp.value);
},
{
  "type": "read",
  "mbean": "java.lang:type=Memory",
  "attribute": "HeapMemoryUsage", "path": "used"
});

jolokia.start(10000);
----

`handle = jolokia.register(callback, request, request,....)`:: This method registers one or more request for being
periodically fetched. `callback` can be either a
function or an object.
+
If a function is given or an object with an attribute
`callback` holding a function, then this
function is called with all responses received as
argument, regardless whether the individual response
indicates a success or error state.
+
If the first argument is an object with two callback
attributes `success` and `error`,
these functions are called for _each_ response
separately, depending whether the response indicates
success or an error state. If multiple requests have been
registered along with this callback object, the callback
is called multiple times, one for each request in the same
order as the request are given.  As second argument, the
handle which is returned by this method is given and as
third argument the index within the list of requests.
+
If the first argument is an object, an additional
`config` attribute with processing
parameters can be given which is used as default for the
registered requests. Requests with a
`config` section take precedence.
+
Furthermore, if a `onlyIfModified:
true` exists in the callback object, then the
`success` and `error`
callbacks are called only if the result changed on the
server side. Currently, this is supported for the
`list` operation only in which case the
callback is only called when MBean has been registered or
deregistered since the last call of the scheduler. If a
single `callback` function is used
which gets all responses for a job at once, then this
function is called only with the responses, which carry a
value. If none of the registered requests produced a
response with value (i.e. the server decided that there
was no update for any request), then a call to the callback function is
skipped completely.
+
`register()` returns a handle which can be used
later for unregistering these requests.
+
In the following example two requests are registered along
with a single callback function, which takes two responses
as arguments:
+
[,javascript]
----
handle = jolokia.register(function(resp1, resp2) {
  console.log("HeapMemory used: " + resp1.value);
  console.log("ThreadCount: " + resp2.value);
},
{
  "type": "read",
  "mbean": "java.lang:type=Memory",
  "attribute": "HeapMemoryUsage",
  "path": "used"
},
{
  "type": "read",
  "mbean": "java.lang:type=Threading",
  "attribute": "ThreadCount"
});
----
+
In the next example, a dedicated `success`
and `error` callback are provided, which are
called individually for each request (in the given
order):
+
[,javascript]
----
jolokia.register(
  {
    "success": function(resp) {
      console.log("MBean: " + resp.mbean + ", attr: " + resp.attribute + ", value: " + resp.value);
    },
    "error": function(resp) {
      console.log("Error: " + resp.error_text);
    },
    config: {
      "serializeException": true
    },
    "onlyIfModified": true
  },
  {
    "type": "list",
    "config": {
      "maxDepth": 2
    }
  },
  {
    "type": "read",
    "mbean": "java.lang:type=Threading",
    "attribute": "ThreadCount",
    "config": {
      "ignoreErrors": true
    }
  },
  {
    "type": "read",
    "mbean": "bla.blu:type=foo",
    "attribute": "blubber"
  }
);
----

`jolokia.unregister(handle)`:: Unregister one or more requests registered with
`handle` so that they are no longer polled
with the scheduler.

`jolokia.jobs()`:: Return an array of handles for all registered jobs. This array can be freely manipulated, its a copy of
the handle list.

`jolokia.start(period)`:: Startup the scheduler for requeting the agent every
`period` milliseconds. If the scheduler is
already running, it adapts its scheduling period according
to the given argument. If no `period` is given,
the period provided during construction time (with the
option `fetchInterval`) is used. The default
value is 30 seconds.

`jolokia.stop()`:: Stop the scheduler. If the scheduler is not running,
nothing happens. The scheduler can be restarted after it
has been stopped.

`jolokia.isRunning()`:: Checks whether the scheduler is running. Returns
`true` if this is the case, `false`
otherwise.
