Chapter 8. Clients

Three client implementations exists for Jolokia: Jmx4Perl, the Perl binding (the grandmother of all clients ;-), a Java library and a Javascript library. This reference describes the client bindings bundled with Jolokia. More JVM based client libraries are planned for inclusiong in Jolokia (e.g. Groovy, Scala or JRuby). Information about Jmx4Perl can be found ???.

8.1. Javascript Client Library

The Jolokia Javascript library provides a Javascript API to the to the Jolokia agent. It comes with two layers, a basic one which allows for sending Jolokia requests to the agent synchronously or asynchronously and one with a simplified API which is less powerful but easier to use. This library supports bulk requests, HTTP GET and POST requests and JSONP for querying agents which are located on a different server.

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 webarchive which also serves this script.

var j4p = new Jolokia("/jolokia");
var value = j4p.getAttribute("java.lang:type=Memory","HeapMemoryUsage","used");
console.log("Heap Memory used: " + value);     

8.1.1. Installation

The Jolokia Javascript library is distributed in two parts, in compressed and uncompressed forms:

jolokia.js and jolokia-min.js

Base library containing the Jolokia object definition which carries the request()

jolokia-simple.js and jolokia-simple-min.js

Library containing the Jolokia simple API and which builds up on jolokia.js It must be included after jolokia.js since it adds methods to the Jolokia object definition.

All four files can be obtained from the download page. For production environments the compressed version is highly recommended since the extensive API documentation included in the original version is stripped off here. For Maven users there is an even better way to integrate them, described in Section 8.1.6, “Maven integration”.

jolokia.js uses jQuery, which must be included as well. If the target platform doesn't support native JSON serialization, json2.js needs to be included as well. As sample HTML head for including all necessary parts looks like:

<head>
  <script src="jquery-1.7.2.js"></script>
  <script src="json2.js"></script>
  <script src="jolokia-min.js"></script>
  <script src="jolokia-simple-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.

8.1.2. Usage

All function of this library are available as methods of the Jolokia object. The options needs to be instantiated as usual and 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 synchronous request for obtaining the agent's version for a agent running on the same server which delivered the Javascript looks like:

var j4p = new Jolokia({url: "/jolokia"});
var response = j4p.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")).

8.1.2.1. 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 Chapter 6, Jolokia Protocol for POST requests. All request types are supported.

The request() expects as its first argument either a single request object or, for bulk requests, an array of request objects. 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 Section 8.1.2.3, “Operational modes” for details.

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

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

8.1.2.2. Request options

Each request can be influenced by a set of optional options 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 (Section 6.3, “Processing parameters”). The known options are summarized in Table 8.1, “Request options”

Table 8.1. Request options

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 dyamically. If a method is selected which doesn't fit to the request, an error is raised.
jsonp Whether the request should be sent via JSONP (a technique for allowing cross domain request circumventing the infamous "same-origin-policy"). This can be used only with HTTP "get" requests.
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 is performed synchronously and gives back the response as return value. The value can be an array of functions which is used for bulk requests to dispatch multiple responses to multiple callbacks. See Section 8.1.2.3, “Operational modes” for details.
error Callback in case a Jolokia error occurs. A Jolokia error is one, in which the HTTP request suceeded with a status code of 200, but the response object contains a 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 an asynchronous operation is performed, the error response is printed to the Javascript console by default.
ajaxError Global error callback called when the Ajax request itself failed. It obtains the same arguments as the error callback given for jQuery.ajax(), i.e. the XmlHttpResonse, a text status and an error thrown. Refer to the jQuery documentation for more information about this error handler.
username A username used for HTTP authentication
password A password used for HTTP authentication
timeout Timeout for the HTTP request
maxDepth Maximum traversal depth for serialization of complex return values
canonicalProperties Defaults to true for canonical (sorted) property lists on object names; if set to "false" then they are turned in their unsorted format.
maxCollectionSize Maximum size of collections returned during serialization. If larger, the collection is returned truncated.
maxObjects Maximum number of objects contained in the response.
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.
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 ommitted 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 (Table 8.1, “Request options”) 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.

8.1.2.3. Operational modes

Requests can be send either synchronously or asynchronously via Ajax. If a success callback is given in the request options, the request is performed asynchronously via an Ajax HTTP request. The callback gets these arguments: a Jolokia JSON response object (see Section 6.1, “Requests and Responses”) and 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 reveive the Jolokia error response as a JSON object.

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

var j4p = new Jolokia("/jolokia");

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

// Bulk request with multiple callbacks
j4p.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 the Ajax request succeeds. In case of an error on the HTTP level, the callback ajaxError is called with the XMLHttpRequest, a textStatus and an optional exception object. It has the same signature as the underlying error callback of the jQuery.ajax() call. (See the jQuery documentation for details).

The Jolokia agent also supports JSONP requests for cases where the Jolokia agent is served on a different server or port than the Javascript client. By default, such access is forbidden by the so called same-origin-policy. To swith on JSONP, the option jsonp should be set to "true".

As explained in Section 6.1, “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 Chapter 5, Proxy Mode ) can only be used with POST.
  • JSONP can only be used with GET and only in asynchronous mode (i.e. a success callback must be given). This is a limitation of the JSONP technique itself.

The restrictions above imply, that JSONP can only be used for single, simple requests and not for JMX proxy calls.

8.1.3. Simple API

Building upon the basic Jolokia.request() method, a simplified access API is available. It is contained in jolokia-simple.js which must be included after jolokia.js. This API provides dedicated method for the various request types and supports all options as described in Table 8.1, “Request options”. 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). Similar, for synchronous operations the value itself is returned. In case of an error, either an error callback is called with the full response object or an Error is thrown for synchronous operations.

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 asynchronous operations (i.e. opts.success != null) it is null. See Section 6.2.1, “Reading attributes (read)” for details.

For example, the following method call can be used to synchronously fetch the current heap memory usage:

var memoryUsed = j4p.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 Section 6.2.2, “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

var gsLoggingWasOn = j4p.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 Section 6.2.3, “Executing JMX operations (exec)” for details.

The following exampled asynchronously fetches a thread dump as a JSON object and logs it into the console:

j4p.execute("java.lang:type=Threading","dumpAllThreads",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 Section 6.2.4, “Searching MBeans (search)” for details.

The following example looks up all application servers available in all domains:

var appServerNames = j4p.search("*:j2eeType=J2EEServer,*");
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 Section 6.2.5, “Listing MBeans (list)”.

This example fetches only the meta information for the attributes of the java.lang:type=OperatingSystem MBean:

var attributesMeta = j4p.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 Section 6.2.6, “Getting the agent version (version)” for more information about this method.

A sample return value for a Glassfish server looks like:

{
  protocol: "4.0",
  agent: "0.82",
  info: {
     product: "glassfish",
     vendor": "Sun",
     extraInfo: {
          amxBooted: false
     }
}

8.1.4. 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:

var j4p = new Jolokia("/jolokia")
handle = j4p.register(function(resp) {
   console.log("HeapMemory used: " + resp.value);
 },
 { type: "READ", mbean: "java.lang:type=Memory", attribute: "HeapMemoryUsage", path: "used"});

j4p.start(10000);
handle = j4p.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 sucess 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 competely.

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:

handle = j4p.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):

j4p.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"});

          
j4p.unregister(handle)

Unregister one or more requests registered with handle so that they are no longer polled with the scheduler.

j4p.jobs()

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

j4p.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.

j4p.stop()

Stop the scheduler. If the scheduler is not running, nothing happens. The scheduler can be restarted after it has been stopped.

j4p.isRunning()

Checks whether the scheduler is running. Returns true if this is the case, false otherwise.

8.1.5. Jolokia as a Cubism Source

Cubism is a Javascript library for plotting time-series data and is based on d3.js. Jolokia comes with a plugin for Cubism and can act as a data source. The usage is quite simple: After creating a Jolokia Cubism source, one or more JSON request can be registered, which are queried periodically. No matter how many requests are registered, only a single HTTP request is sent to the server after each period. Cubism is then responsible for plotting the data.

Figure 8.1, “Horizon Chart for Heap-Memory Usage” shows a sample for a memory plot. More examples can be found on this page.

Figure 8.1. Horizon Chart for Heap-Memory Usage

Horizon Chart for Heap-Memory Usage

jolokia-cubism.js can be downloaded from the downlad page and also comes with a minified version. As dependencies it requires jolokia.js, JQuery, Cubism and d3.js. jolokia-cubism.js registers itself as an AMD module if running within an AMD environment.

In order to use Jolokia with Cubism, you first need to create a Cubism context. Next use context.jolokia() for creating a connection to the Jolokia agent.

var context = cubism.context();
  
// Create a source for Jolokia metrics pointing to the agent 
// at 'http://jolokia.org/jolokia'
var jolokia = context.jolokia("http://jolokia.org/jolokia");

The method context.jolokia() can take various kind of arguments:

  • A single string as in the example above is used as the agent's URL. Additionally, options as key-value pairs can be given as an additional argument. The possible keys are described in Table 8.1, “Request options”. If the URL is omitted, but only an option object is provided, then this object must also contain a key url for specifying the agent URL.

  • Alternatively, an already instantiated Jolokia object can be provided as single argument, which then is used for all communications to the server.

From this source object, a metric object can be easily created. This metric object embrasses one or more Jolokia requests which are send to the server periodically. The response(s) are then used for calculating a single numerical value which gets plotted. For example:

// Read periodically the Heap-Memory use and take 'HeapMemory Usage' as name/label.
var metricMem = jolokia.metric({
                      type: 'read', 
                      mbean: 'java.lang:type=Memory',
                      attribute: 'HeapMemoryUsage',
                      path: 'used'
                  },"HeapMemory Usage"); 

// Example for a callback function for evaluating responses
// dynamically. In this case, the first
// argument is a function, which gets feed with all response objects
// (one in this case). The requests objects are given next, and an
// options object as last argument. 
var metricReq = jolokia.metric(
    function (resp) {
        var attrs = resp.value;
        var sum = 0;
        for (var key in attrs) {
            sum += attrs[key].requestCount;
        }
        return sum;
    },
    { 
        type: "read",
        mbean: "Catalina:j2eeType=Servlet,*",
        attribute:"requestCount"
    }, 
    { name: "All", delta: 101000});

metric() is a factory method which can be called in various ways.

  • If the first argument is a Jolokia request object (i.e. not a function), this request is used for sending requests periodically.

  • If the first argument is a function, this function is used for calculating the numeric value to be plotted. The rest of the arguments can be one or more request objects, which are registered and their responses are put as arguments to the given callback function.

  • The last argument, if an object but not a Jolokia request (i.e. there is no type key), is taken as an option object which is described below.

  • Finally, if the last argument is a pure string, then this string is used as name for the chart.

An object which can be given as last argument is used for fine tuning the metrics:

name

Name used in charts. The name can also be given alternatively as a string directly as last argument (but then without any other options)

delta

Delta value in milliseconds for creating delta (velocity) charts. This is done by taking the value measured that many milliseconds ago and substract them from each other..

keepDelay

How many milliseconds before the oldest shown value should be kept in memory, which e.g. is necessary for delta charts. When delta is given, this value is implicetly set.

One or more metric objects can now be converted to charts and added to a website with d3.js. This is done in the usual cubism way as described here. In our example, in order to append charts to a div with id chart the following code can be used:

// Use d3 to attach the metrics with a specific graph type 
// ('horizon' in this case) to the document
d3.select("#charts").call(function(div) {
    div.append("div")
        .data([metricMem, metricReq])
        .call(context.horizon())
});

For a complete API documentation please refer to the Cubism API.

8.1.6. Maven integration

For maven users' convenience, the Jolokia Javascript package is also available as a JavaScript artifact. It can be easily included with help of the javascript-maven-plugin.

The following example shows a sample configuration which could be used within a pom.xml:

<project>
...
  <dependencies>
    <dependency>
      <groupId>org.jolokia</groupId>
      <artifactId>jolokia-client-javascript</artifactId>
      <type>javascript</type>
      <version>1.0.5</version>
    </dependency>
    ....
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>com.devspan.mojo.javascript</groupId>
        <artifactId>javascript-maven-plugin</artifactId>
        <version>0.9.3</version>
        <extensions>true</extensions>
        <configuration>
          <useArtifactId>false</useArtifactId>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>war-package</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      ......
    </plugins>
   ....
  </build>
  ...
  <pluginRepositories>
    <pluginRepository>
      <id>sonatype-oss</id>
      <url>https://oss.sonatype.org/content/groups/public</url>
    </pluginRepository>
  </pluginRepositories>
</project>

Then, in your webapp project, jolokia.js, jolokia-simple.js and json2.js can be found in the scripts/lib directory (relative to the top level of you WAR). In order to include it in your HTML files use something like this:

<head>
  <script src="jquery-1.7.2.js"></script>
  <script src="scripts/libk/json2.js"></script>
  <script src="scripts/lib/jolokia.js"></script>
  <script src="scripts/lib/jolokia-simple.js"></script>
</head>

jQuery.js has to be included on its own, though and is not included within the dependency. If the compressed version of jolokia.js should be used, add a classifier="compressed" to the jolokia-client-javascript dependency, and include scripts/lib/jolokia-min.js

A full working example can be found in the Jolokia src at client/javascript/test-app/pom.xml.

8.2. Java Client Library

The Java client library provides an easy access to the Jolokia agent from within Java. Since JSR-160 connectors themselved provide Java based remote access to MBeans one might wonder about the benefits of a Jolokia Java binding. There are several, though:

  • It provides a typeless access to remote MBeans. The big advantage is that for any non-OpenMBean access to custom typed objects is still possible without having the type information locally in the classpath.
  • Jolokia can be used in setups where JSR-160 connectors can not be used. I.e. in firewall secured environments it is much easier to get through to a Jolokia Agent than to an JSR-160 connetor using RMI as transport protocol.
  • Remoteness is explicit in this API instead of JSR-160 connector's seeked transparent remoteness. RMI has some arguable conceptually advantages, but hiding all remote aspects proved to have quite some disadvantages when it comes to the programming model. Explicite awareness of a 'heavy-weight' remote call is better than false transparency in order to know the price tag.

The Java client library follows a strict request-response paradigm, much like the underlying HTTP. It uses generics heavily and can be centered around three classes: J4pClient is the client side agent, which has various variants of a execute() for sending requests. This method takes one or more J4pRequest objects as arguments and returns one or more J4pResponse objects as result.

But before we got into the details, the next section gives a first tutorial to get a feeling how the API can be used.

8.2.1. Tutorial

As seen in the following example, the usage is quite easy. First a, client object client is created pointing to a Jolokia agent at http://localhost:8080/jolokia. A read request for querying the heap memory usage from the MemoryMXBean is created and then send via the execute() to the agent. The response returned is of type J4pReadResponse and holds the result which finally is printed out to standard output.

   
import org.jolokia.client.J4pClient;
import org.jolokia.client.request.*;

public class MemoryDemo {
    public static void main(String[] args) {
       J4pClient client = new J4pClient("http://localhost:8080/jolokia");
       J4pReadRequest request = 
           new J4pReadRequest("java.lang:type=Memory","HeapMemoryUsage");
       request.setPath("used");
       J4pReadResponse response = client.execute(request);
       System.out.println("Memory used: " + response.getValue());
    }
}

In order to compile and run this sample, two support libraries are required in addition to jolokia-client-java.jar (Download):

For maven users, the following dependency is sufficient (it will include the other two as transitive dependencies):

 <dependency>
   <groupId>org.jolokia</groupId>
   <artifactId>jolokia-client-java</artifactId>
   <version>1.2.2</version>
 </dependency>    

8.2.2. J4pClient

J4pClient is the entry point for sending requests to a remote Jolokia agent. It can be created in multiple ways. For simple cases, public constructors are provided taking the mandatory Jolokia agent URL and optionally a org.apache.http.client.HttpClient instance which is used for the HTTP business. The recommended style is to use the J4pClientBuilder, though. This way, all parameters for the HTTP communication can easily be set:

J4pClient j4p = J4pClient.url("http://localhost:8080/jolokia")
                         .user("roland")
                         .password("s!cr!t")
                         .authenticator(new BasicAuthenticator().preemptive())
                         .connectionTimeout(3000)
                         .build();

The builder supports the following parameters with the given defaults:

Table 8.2. J4pClient parameters

Parameter Description Default
url The URL to the Jolokia agent. This is the only mandatory parameter.
user User name when authentication is used. If not set, no authentication is used. If set, password must be set, too
password Password used for authentication. Only used when user is set.
authenticator Implementation of J4pAuthenticator. The Java client comes with one implementation BasicAuthenticator for using basic authentication. This class supports also preemptive authentication. Call preemptive() to switch this on (see above for an example). Basic authentication is the default if no other authenticator is set.Only used when user is set, too.
target A JMX JSR-160 ServiceURL which should be used by the agent as the real target. This parameter should be set if the client is used for accessing the agent in Chapter 5, Proxy Mode .
targetUser The JSR-160 user to use when using the proxy mode. If not given (and target is set), then no authentication is used for JSR-160 communication.
targetPassword JSR-160 Password to use for the proxy mode.
connectionTimeout The timeout in milliseconds until a connection is established. A timeout value of zero is interpreted as an infinite timeout. 20000
pooledConnection Specifies, that the underlying HttpClient should use pooled connection manager, which is thread safe and can service connection requests from multiples threads simultaneously. This is important if the J4pClient is to be used in a multi threaded context. The size of the pool is restricted by the parameter maxTotalConnection. ThreadSafeClientConnManager is the underlying connection manager. Pooled connections are the default.
singleConnection Specifies that single connection should be used which maintains only one active connection at a time. Even though J4pClient is still thread-safe it ought to be used by one execution thread only. The underlying connection manager is SingleClientConnManager Pooled connections are the default.
maxTotalConnections Defines the number of total connections to be pooled. It is only used when pooledConnection is used. 20
maxConnectionPoolTimeout Defines the timeout for waiting to obtain a connection from the pool. This parameter is only used when pooledConnections are used. 500
socketTimeout Defines the socket timeout (SO_TIMEOUT) in milliseconds, which is the timeout for waiting for data or, put differently, a maximum period inactivity between two consecutive data packets. A timeout value of zero is interpreted as an infinite timeout. 0
contentCharset Defines the charset to be used per default for encoding content body. ISO-8859-1
expectContinue Activates Expect: 100-Continue handshake for the entity enclosing methods. The purpose of the Expect: 100-Continue handshake to allow a client that is sending a request message with a request body to determine if the origin server is willing to accept the request (based on the request headers) before the client sends the request body. The use of the Expect: 100-continue handshake can result in noticable peformance improvement for entity enclosing requests that require the target server's authentication. true
tcpNoDelay Determines whether Nagle's algorithm is to be used. The Nagle's algorithm tries to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase in bandwidth consumption. true
socketBufferSize Determines the size of the internal socket buffer in bytes used to buffer data while receiving and transmitting HTTP messages. 8192

The J4pClient provides various variants of a execute() method, which takes either one single request or a list of requests. For a single request, the preffered HTTP method (GET or POST) can be specified optionally. The List<R> argument can be used type only for a homogenous bulk request, i.e. for multiple requests of the same time. Otherwise an untyped list must be used.

Each request can be tuned by giving a map of processing options along with their values to the execute method. The possible options are shown in table Table 8.3, “J4pClient query parameters”.

Table 8.3. J4pClient query parameters

J4pQueryParameter enum Description
MAX_DEPTH Maximum traversal depth for serialization of complex objects. Use this with a "list" request to restrict the depth of the returned meta data tree.
MAX_COLLECTION_SIZE Maximum size of collections returned during serialization. If larger, a collection is truncated to this size.
MAX_OBJECTS Maximum number of objects returned in the response's value.
IGNORE_ERRORS Option for ignoring errors during JMX operations and JSON serialization. This works only for certain operations like pattern reads and should be either true or false.
INCLUDE_STACKTRACE Whether to include a stack trace in the response when an error occurs. The allowed values are true for inclusion, false if no stacktrace should be included or runtime if only RuntimeExceptions should be included. Default is true.
SERIALIZE_EXCEPTION Whether to include a JSON serialized version of the exception. If set to true, the exception is added under the key error_value in the response. Default is false.
CANONICAL_NAMING Whether property keys of ObjectNames should be ordered in the canonical way or in the way that they are created. The allowed values are either true in which case the canonical key order (== alphabetical sorted) is used or false for getting the keys as registered. Default is true

8.2.3. Request types

For each request type a dedicated request object is provided which all are subclasses from J4pRequest. For all requests it can be specified which HTTP method is to be used by setting the property preferredHttpMethod to either GET or POST. Each request type has a corresponding response type which used for the return values of the J4pClient.execute().

The constructor of each kind of request can take a J4pTargetConfig as argument for using a request in Chapter 5, Proxy Mode . This configurational object holds the JMX service url and (optionally) credentials for JSR-160 authentication. When given, this proxy target specification overrides any default proxy configuration set during the initialization of the J4pClient.

J4pReadRequest and J4pReadResponse

J4pReadRequest is a read request to get one or more attributes from one or more MBeans within a single request. Various constructor variants can be used to specify one or more attributes along with the ObjectName (which can be a pattern). A path can be set as property for specifying an inner path, too.

J4pReadResponse is the corresponding response type and allows typed acces to the fetched value for a single attribute fetch or to multiple values for a multi attribute read. In the latter case, the found object and attributes names can be retrieved as well.

For more information on fetching the value of multiple attributes and multiple MBeans at once, please refer to Section 6.2.1, “Reading attributes (read)” or the Javadoc of J4pReadResponse.

J4pWriteRequest and J4pWriteResponse

A J4pWriteRequest is used to set the value of an MBean attribute. Beside the mandatory object and attribute name the value must be give in the constructor as well. Optionally a path can be provided, too. Only certain types for the given value can be serialized properly for calling the Jolokia agent as described in Section 6.4.2, “Request parameter serialization”.

The old value is returned as J4pWriteResponse's value.

J4pExecRequest and J4pExecResponse

J4pExecRequests are used for executing operation on MBeans. The constructor takes as mandatory arguments the MBean's object name, the operation name and any arguments required by the operation. Only certain types for the given arguments can be serialized properly for calling the Jolokia agent as described in Section 6.4.2, “Request parameter serialization”.

The returned J4pExecResponse contains the return value of the operation called.

J4pSearchRequest and J4pSearchResponse

A J4pSearchRequest contains a valid single MBean object name pattern which is used for searching MBeans.

The J4pSearchResponse holds a list of found object names.

J4pListRequest and J4pListResponse

For obtaining meta data on MBeans a J4pListRequest should be used. It can be used with a inner path to obtain only a subtree of the response, otherwise the whole tree as described in Section 6.2.5.3, “List response” is returned. With the query parameter maxDepth can be used to restrict the depth of returned tree.

The single value of a J4pListResponse is a tree (or subtree) as a JSON object, which has the format described in Section 6.2.5.3, “List response”.

J4pVersionRequest

A J4pVersionRequest request the Jolokia agent's version information and takes no argument.

The J4pVersionResponse returns the agent's version (agentVersion), the protocol version (protocolVersion), the applicaton server product name (product), the vendor name (vendor) and any extra info (extraInfo) specific to the plattform the Jolokia is running on.

8.2.4. Exceptions

In case of an error when executing a request a J4pException or one its subclass is thrown.

J4pConnectException

Exception thrown when the connection to the server fails. It contains the original ConnectException as nested value.

J4pTimeoutException

Exception thrown in case of an timeout. The nested exception is of type ConnectTimeoutException.

J4pRemoteException

Generic exception thrown when an exception occured on the remote side. This is the case when the JSON response obtained is an error response as described in Section 6.1.3, “Responses”. The error type, error value, the status, the request leading to this error and the remote stacktrace as string) can be obtained from this exception.

J4pBulkRemoteException

Exception thrown when a bulk request fails on the remote side. This contains a mixed list which contains the J4pRemoteException occured as well as the J4pResponse objects for the requests, which suceeded. The list obtained by getResults() contains these objects in the same order as the list of requests given to execute. All responses und remote exceptions can also be obtained seperately in homogenous lists.

J4pException

Base exception thrown, when no other exception fits, i.e. when the exception happened on the client side. The original exception is contained as nested exception.