Monday, June 26, 2017

Java Command-Line Interfaces (Part 3): jbock

In the first two posts of this series on command-line parsing in Java, I looked at the Apache Commons CLI and args4j libraries. In this third post in the series, I look at jbock, the self-described "curiously simple CLI parser."

My posts on command-line parsing in Java have used examples based on providing a required file name and an optional verbose flag to the Java application. The same approach is used in this post to demonstrate jbock 1.8. The full source code for the example class is available on GitHub, but the code generated by jbock (Main_Parser) is not available as it can be generated.

The approach jbock uses for command-line processing is different than that used by the two previously covered parsing libraries. The previously covered libraries required Java code for parsing command-line arguments to be built against and executed against the libraries' JARs. In other words, the libraries' JARs needed to be on both the compile-time (javac) classpath and on the runtime Java launcher (java) classpath. The jbock approach instead relies on inclusion of the jbock JAR only at compile time. The jbock approach generates Java source code that is completely independent of the jbock library. One could, for example, choose to run jbock to generate these Java source code files once and then version control those generated files and only build and run against the generated files from that point on without needing to build or run against jbock's JAR. The only time the jbock JAR is required is when the generated Java source needs to be regenerated. Because the generated code is generated based on annotations on custom Java classes, it is likely that the jbock code generation would be executed in most cases as part of a normal build rather than version controlling the generated source.

In most situations, I'd use a custom class with a name such as "Arguments" or "CommandLine" when using jbock to parse command-line arguments. However, for this post, I am using a simple Main class to be more similar of an example to the approach used with the other command-line parsing libraries in other posts in this series. Like args4j, jbock uses annotations for the "definition" phase of command-line processing. However, jbock's annotations are on the class's constructor and its arguments rather than args4j's approach of annotating class fields. The jbock constructor-based annotations approach is demonstrated in the next code listing.

jbock "Definition" of Command-Line Options

@CommandLineArguments
public Main(
   @ShortName('v') @LongName("verbose") @Description("Verbosity enabled?")
   final boolean newVerbose,
   @ShortName('f') @LongName("file") @Description("File name and path")
   final Optional<String> newFileName)
{
   verbose = newVerbose;
   file = newFileName.orElse("");
}
// . . .

The "parsing" stage of command-line processing with jbock is demonstrated in the next code listing.

"Parsing" Command-line Options with jbock

final Main_Parser parser = new Main_Parser();
final Main_Parser.Binder binder = parser.parse(arguments);
final Main main = binder.bind();

The Main_Parser class shown in the above code listing is generated by jbock based on the annotations shown in the first code listing. The jbock library processes the annotations of the Main class to determine how to build the Main_Parser class. The generated class's name is based on the name of the class with jbock annotations and concatenated with _Parser. For example, had my class with jbock annotated constructor and constructor arguments been named "Arguments", the generated class would be named "Arguments_Parser".

After the instance of the generated Main_Parser class has had parse invoked on the command-line arguments, that instance's bind() method is invoked to return an instance of the original annotated Main class. The "interrogation" process at this point consists solely of accessing the attributes of that Main instance via its public "get" methods. This is demonstrated in the next code listing.

"Interrogation" Stage of Command-line Processing with jbock

out.println("The file '" + main.getFile() + "' was provided and verbosity is set to '"
   + main.isVerbose() + "'.");

The screen snapshot that follows demonstrates the code in action using jbock to parse the command-line options.

If help or usage information is desired, this can be retrieved from the generated *_Parser (Main_Parser in this case) class as well. Specifically, the generated *_Parser class includes a nested Option enum representing the various options. One can iterate over those option's enum values to retrieve metadata about each option. In the code listing below, the describe(int) method is invoked on each option's enum value (the passed-in integer is the number of spaces to indent).

Obtaining Usage Details with jbock

final Main_Parser parser = new Main_Parser();
if (arguments.length < 1)
{
   for (final Main_Parser.Option option : Main_Parser.Option.values())
   {
      out.println(option.describe(3));
   }
   System.exit(-1);
}

The screen snapshot shown next demonstrates this code in action to print out the options and their descriptions.

The source code discussed in this post is available on GitHub.

Here are some additional characteristics of jbock to consider when selecting a framework or library to help with command-line parsing in Java.

  • jbock is available as open source.
  • The current version of jbock (1.8) requires Java SE 8.
  • jbock has no third-party or external dependencies.
  • The jbock 1.8 JAR (jbock-1.8.jar) is approximately 131 KB in size, but this is not as significant as for similar libraries because this JAR is not required at runtime (generated code is independent of the JAR).
  • I did not demonstrate jbock's enforcement of the presence of required command-line parameters because it intentionally does not support that feature. The README states, "Deliberately simple: No converters, default values or required checking. With java 8, it's easy to add this stuff by hand."

The most obvious characteristic of jbock that distinguishes it from most other Java-based command-line parsing libraries is the generation of parsing code entirely at compile time that leaves no runtime dependencies on the jbock library. This would be an obvious advantage in situations where there is concern about the number of classes loaded or the size of the expressed classpath. The README lists multiple items that "set [jbock] apart." These include "no reflection, purely static analysis" and "convenient, flexible property binding via constructor."

Additional References

Thursday, June 22, 2017

Java Command-Line Interfaces (Part 2): args4j

In my previous post, I looked at parsing command-line arguments in Java applications using Apache Commons CLI. In this post, I look at doing the same using a different library: args4j.

args4j takes a different approach to specifying which command-line arguments the Java application should expect than that used by Commons CLI. While Commons CLI expects objects representing the options to be individually and explicitly instantiated, args4j uses custom annotations to facilitate this "definition" stage of command-line arguments processing. Command-line options are expected to be instance-level fields on the class and are annotated with the @org.kohsuke.args4j.Option annotation. The characteristics of each command-line argument are included as attributes of this @Option annotation.

The simple application demonstrated in this post is similar to that used in my previous post and focuses on an optional and valueless -v option for specifying verbosity and a required -f option which expects a value that represents the file path and name. The next code listing demonstrates use of args4j's @Option annotation to set up these command-line argument as annotation on class data members.

args4j Definition of Command-line Arguments via @Option Annotations

@Option(name="-v", aliases="--verbose", usage="Print verbose status.")
private boolean verbose;

@Option(name="-f", aliases="--file", usage="Fully qualified path and name of file.", required=true)
private String fileName;

As the above code listing demonstrates, it is easy to specify the name of the options, their usage, and whether they are required or not (default is optional). The presence of the private modifier above makes it obvious that these are attributes defined at a class level. Because there is no static modifier, we see that these are instance variables that have been annotated.

To parse the command-line options, one simply needs to instantiate a CmdLineParser and pass the command-line arguments to its parseArguments(String...) method:

Parsing Command-line Arguments in args4j

final CmdLineParser parser = new CmdLineParser(this);
try
{
   parser.parseArgument(arguments);
}
catch (CmdLineException clEx)
{
   out.println("ERROR: Unable to parse command-line options: " + clEx);
}

In the first line of Java code just shown, this is the reference to the instance of the class in which the member variables shown above are defined and annotated with the @Option annotation. In this case, I used this because the same class that defines those options is the one calling this parsing method. To do this in the same class, I needed to have an instance (non-static) method called doMain defined in the class and invoked by the class's main function (this is shown in the complete code listing toward the end of this post). The command-line arguments as received from the class's main(final String[]) function are the array of Strings passed to the parseArguments(String[]) method.

The next two screen snapshots demonstrate application of the described code based on args4j to parsing the command-line arguments. The first image shows combinations of the short and long options for the two options. The second image shows the automatic reporting of the case where a required command-line argument was not provided.

An important feature of a command line parsing library is the ability to display usage or help information. The next code listing demonstrates an example of doing this with args4j's CmdLineParser.printUsage(OutputStream) method.

Printing Usage Information with args4j

final CmdLineParser parser = new CmdLineParser(this);
if (arguments.length < 1)
{
   parser.printUsage(out);
   System.exit(-1);
}

The usage information printed out by default by args4j is depicted in the next screen snapshot.

This post has demonstrated using arg4j to achieve some of the most common functionality related to command-line parsing in Java applications including option "definition", command-line arguments "parsing", "interrogation" of the parsed command-line arguments, and help/usage details related to the command-line arguments. The full code listing for the class partially represented above in code listings is shown now (also available on GitHub, which version is subject to tweaks and improvements).

Full Code Listing for args4j Demonstration Main.java

package examples.dustin.commandline.args4j;

import static java.lang.System.out;

import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import java.io.IOException;

/**
 * Demonstrate args4j.
 */
public class Main
{
   @Option(name="-v", aliases="--verbose", usage="Print verbose status.")
   private boolean verbose;

   @Option(name="-f", aliases="--file", usage="Fully qualified path and name of file.", required=true)
   private String fileName;

   private void doMain(final String[] arguments) throws IOException
   {
      final CmdLineParser parser = new CmdLineParser(this);
      if (arguments.length < 1)
      {
         parser.printUsage(out);
         System.exit(-1);
      }
      try
      {
         parser.parseArgument(arguments);
      }
      catch (CmdLineException clEx)
      {
         out.println("ERROR: Unable to parse command-line options: " + clEx);
      }
      out.println("The file '" + fileName + "' was provided and verbosity is set to '" + verbose + "'.");
   }

   /**
    * Executable function demonstrating Args4j command-line processing.
    *
    * @param arguments Command-line arguments to be processed with Args4j.
    */
   public static void main(final String[] arguments)
   {
      final Main instance = new Main();
      try
      {
         instance.doMain(arguments);
      }
      catch (IOException ioEx)
      {
         out.println("ERROR: I/O Exception encountered: " + ioEx);
      }
   }
}

Here are some additional characteristics of args4j to consider when selecting a framework or library to help with command-line parsing in Java.

  • args4j is open source and licensed with the MIT License.
  • Current version of args4j (2.33) requires J2SE 5.
  • args4j does not require any third-party libraries to be downloaded or referenced separately.
  • The args4j 2.33 main JAR (args4j-2.33.jar) is approximately 152 KB in size.
  • The Maven Repository shows 376 dependencies on args4j including OpenJDK's JMH Core and Jenkins (not surprising given Kohsuke Kawaguchi's involvement in both).
  • args4j has been around for a while; its 2.0.3 release was in January 2006 and it's been around in some form since at least 2003.
  • args4j allows a command-line parameter to be excluded from the usage output via "hidden" on the @Option annotation.
  • args4j allows for relationships between command-line arguments to be specified and enforced. This includes the ability to specify when two arguments cannot be supplied at the same time ("forbids") and when the presence of an argument only makes sense when another argument is also provided ("depends").
  • args4j supports use of enum-typed class attributes for cases where a finite set of values is applicable to the option. The @Option documentation describes how to do this under the "Enum Switch" section.
  • args4j provides extensibility and customizability of command-line arguments parsing via its OptionHandler class.

The args4j library is easy to use and allows for highly readable code. Perhaps the biggest consideration when deciding whether to use args4j is deciding how comfortable one is with using annotations for specifying the command-line parameters' definitions.

Additional References

Tuesday, June 20, 2017

Java Command-Line Interfaces (Part 1): Apache Commons CLI

Although I typically use Groovy to write JVM-hosted scripts to be run from the command-line, there are times when I need to parse command-line parameters in Java applications and there is a plethora of libraries available for Java developers to use to parse command-line parameters. In this post, I look at one of the best known of these Java command line parsing libraries: Apache Commons CLI.

I have blogged on Apache Commons CLI before, but that post is over eight years old and describes Apache Commons CLI 1.1. Two classes that I demonstrated in that post, GnuParser and PosixParser, have since been deprecated. The examples in this current post are based on Apache Commons CLI 1.4 and use the newer DefaultParser that was introduced with CLI 1.3 to replace GnuParser and PosixParser.

The Apache Commons CLI documentation's "Introduction" explains how Commons CLI accomplishes the "three stages [of] command line processing" ("definition", "parsing", and "interrogation"). These three stages map in Commons CLI to classes Option and Options ("definition"), to interface CommandLineParser ("parsing"), and to class CommandLine ("interrogation").

For the examples built here with Apache Commons CLI, the expected command-line arguments are relatively simple. One argument is optional and, when specified, indicates that verbose output is enabled. The other argument is required and is used to specify a file to be processed by the imaginary application. The optional argument does not have a value associated with the flag and is expressed as -v or --verbose. The required argument should be followed by a value which is the path and name of the file. This flag is either -f or --file. The next code listing demonstrates using Commons CLI's Option.Builder (introduced with Commons CLI 1.3) to build up the expected options as part of the "definition" stage.

Example of Using Apache Commons CLI Option.Builder for "Definition Stage

/**
 * "Definition" stage of command-line parsing with Apache Commons CLI.
 * @return Definition of command-line options.
 */
private static Options generateOptions()
{
   final Option verboseOption = Option.builder("v")
      .required(false)
      .hasArg(false)
      .longOpt(VERBOSE_OPTION)
      .desc("Print status with verbosity.")
      .build();
   final Option fileOption = Option.builder("f")
      .required()
      .longOpt(FILE_OPTION)
      .hasArg()
      .desc("File to be processed.")
      .build();
   final Options options = new Options();
   options.addOption(verboseOption);
   options.addOption(fileOption);
   return options;
}

The "Builder" pattern implemented for Apache Commons CLI as shown in the above example features the benefits of the builder pattern such as creating an Option in a fully completed state in one statement and use of highly readable builder methods to set that instance's various fields. My older post on Apache Commons CLI demonstrates use of the alternate traditional constructor approach to instantiating Option instances.

With the command-line options defined, it's time to move to the "parsing" stage and the next code listing demonstrates how to parse with Apache Commons CLI by simply invoking the method CommandLinePaser.parse().

Parsing Command-line Options with Commons CLI

/**
 * "Parsing" stage of command-line processing demonstrated with
 * Apache Commons CLI.
 *
 * @param options Options from "definition" stage.
 * @param commandLineArguments Command-line arguments provided to application.
 * @return Instance of CommandLine as parsed from the provided Options and
 *    command line arguments; may be {@code null} if there is an exception
 *    encountered while attempting to parse the command line options.
 */
private static CommandLine generateCommandLine(
   final Options options, final String[] commandLineArguments)
{
   final CommandLineParser cmdLineParser = new DefaultParser();
   CommandLine commandLine = null;
   try
   {
      commandLine = cmdLineParser.parse(options, commandLineArguments);
   }
   catch (ParseException parseException)
   {
      out.println(
           "ERROR: Unable to parse command-line arguments "
         + Arrays.toString(commandLineArguments) + " due to: "
         + parseException);
   }
   return commandLine;
}

Note that this code using a newer version of Apache Commons CLI instantiates a DefaultParser for doing the parsing rather than a PosxParser or GnuParser as was done in the older code.

With the command-line objects defined and the command-line parsed, it is time for the interrogation stage. The next code listing demonstrates Apache Commons CLI's support for command-line interrogation.

Interrogating Command-line with Commons CLI

final boolean verbose =
   commandLine.hasOption(VERBOSE_OPTION);
final String fileName =
   commandLine.getOptionValue(FILE_OPTION);
out.println("The file '" + fileName + "' was provided and verbosity is set to '" + verbose + "'.");

The above code listing demonstrates use of CommandLine.hasOption() to determine if an option's particular flag is present without regard for whether a value is provided for that flag (appropriate for -v/--verbose in our example). Likewise, the code shows that CommandLine.getOptionValue() can be used to obtain the value associated with the the provided command-line flag (appropriate for the -f/--file option in our example).

The next screen snapshot demonstrates the output from the simple example whose code listings were shown above and they demonstrate the support for the verbosity and file path/location command-line options described above.

The second screen snapshot demonstrates Commons CLI' output when the command-line parameters don't include a required command-line argument.

A useful piece of functionality for any framework for building Java command-line parsing is the ability to support usage and help information. This is accomplished via Commons CLI's HelpFormatter. The next code listing demonstrates using HelpFormatter for printing help and usage information and the screen snapshot following the code listing demonstrates the appearance of the help and usage when employed.

Acquiring "usage" and "help" Details with Commons CLI

/**
 * Generate usage information with Apache Commons CLI.
 *
 * @param options Instance of Options to be used to prepare
 *    usage formatter.
 * @return HelpFormatter instance that can be used to print
 *    usage information.
 */
private static void printUsage(final Options options)
{
   final HelpFormatter formatter = new HelpFormatter();
   final String syntax = "Main";
   out.println("\n=====");
   out.println("USAGE");
   out.println("=====");
   final PrintWriter pw  = new PrintWriter(out);
   formatter.printUsage(pw, 80, syntax, options);
   pw.flush();
}

/**
 * Generate help information with Apache Commons CLI.
 *
 * @param options Instance of Options to be used to prepare
 *    help formatter.
 * @return HelpFormatter instance that can be used to print
 *    help information.
 */
private static void printHelp(final Options options)
{
   final HelpFormatter formatter = new HelpFormatter();
   final String syntax = "Main";
   final String usageHeader = "Example of Using Apache Commons CLI";
   final String usageFooter = "See http://marxsoftware.blogspot.com/ for further details.";
   out.println("\n====");
   out.println("HELP");
   out.println("====");
   formatter.printHelp(syntax, usageHeader, options, usageFooter);
}

This post has demonstrated using Apache Commons CLI to achieve some of the most common functionality related to command-line parsing in Java applications including option "definition", command-line arguments "parsing", "interrogation" of the parsed command-line arguments, and help/usage details related to the command-line arguments. Here are some additional characteristics of Apache Commons CLI to consider when selecting a framework or library to help with command-line parsing in Java.

  • Apache Commons CLI is open source and licensed with the Apache License, Version 2.0.
  • Current version of Apache Commons CLI (1.4) requires J2SE 5 or later.
  • Apache Commons CLI does not require any third-party libraries to be downloaded or referenced separately.
  • The Apache Commons CLI 1.4 main JAR (commons-cli-1.4.jar) is approximately 53 KB in size.
  • Apache Groovy provides out-of-the-box command-line parsing capabilities based on Apache Commons CLI via CliBuilder.
  • The Maven Repository shows almost 1800 dependencies on Apache Commons CLI including Apache Groovy.
  • Apache Commons CLI has been around for a while; its initial 1.0 release was in November 2002.
  • Commons CLI supports both long and short syntax for command-line arguments. Its main page lists support for these types of option formats (and that page includes examples of each style):
    • "POSIX like options" (single hyphen)
    • "GNU like long options" (double hyphen)
    • "Java like properties" (using -D)
    • "Short options with value attached"
    • "Long options with single hyphen"

For me, one of the biggest advantages of Apache Commons CLI when implementing command-line interfaces in simple Java applications is that I'm already familiar with Groovy's built-in use of CliBuilder. Because I use Groovy far more often for simple command-line based scripts and tools than I use Java, this Groovy familiarity with the basic Apache Commons CLI usage is helpful when moving back to Java.

Additional References

Monday, June 5, 2017

jhsdb: A New Tool for JDK 9

I like to use the command-line tools provided with the JDK in the early steps of analyzing performance and other issues with Java-based applications and have blogged on tools such as jcmd, jps, jstat, jinfo, jhat and jmap, jrunscript, jstack, and jdeps. JDK 9 is bringing new command-line tools with multiple tools specifically related to new JDK 9 features such as modularity (jlink and jmod) and enhanced deprecation (jdeprscan). In this post, I focus on a new command-line tool delivered with JDK 9 for dealing with performance and serviceability issues: jhsdb.

The jhsdb tool is described on its Oracle JDK 9 Documentation Early Access page, "You use the jhsdb tool to attach to a Java process or to launch a postmortem debugger to analyze the content of a core-dump from a crashed Java Virtual Machine (JVM)." The tool comes with several "modes" and several of these modes correspond in name and function with individual command-line tools available in previous JDK distributions. The jhsdb tool not only provides a single tool that encompasses functionality of multiple other tools, but it also provides a single, consistent approach to applying these different functions. For example, the jhsdb command-line syntax for getting help for each of the "modes" is identical.

The jhsdb tool can be attached and applied to a running JVM (including one that is hanging) via its process identifier (PID) similar to how several other tools (including jcmd) work. The jhsdb tool can also be used to analyze core information associated with a crashed JVM if the core file and executable are provided. As an example of the consistency jhsdb provides, all of its mode support the "common options" --pid (to specify target JVM's process ID), --exe (to specify target executable), --core (to specify target core dump file), and --help (to display options specific to each mode).

The next series of snapshots demonstrates use of the --help option with the main jhsdb command and with each of several of jhsdb's "modes." One observation that can be made is that the common options --pid, --core, and --exe are offered by all the modes. The obvious inference from this is that the specific functions supported in each mode are those other than those "common" options.

jhsdb "jstack" Mode

The --help for the jhsdb mode jstack has two specific functionality options: --locks and --mixed. These are demonstrated in the following two screen snapshots.

The screen snapshots just shown demonstrate that the jstack mode of the jhsdb tool provides us with deadlock detection details, information on thread locks, and an overview of the native frames and Java frames.

jhsdb "jmap" Mode

The --help for jhsdb mode jmap shows several functions supported by that mode. When jhsdb jmap is executed with only the --pid or only with the --exe/--core combination, the output is similar to that provided by the Linux pmap command.

As one would expect, the jmap mode of the jhsdb provides functions similar to those provided by the separate but similarly named jmap command. These include heap dump (--heap), class histogram (--histo), classloader statistics (--clstats), and finalizer information (--finalizerinfo) and are demonstrated in the following four screen snapshots.

jhsdb "jinfo" Mode

Not surprisingly, the jinfo mode of the jhsdb command provides functionality that overlaps with that provided by the jinfo command. Specifically, the jhsdb's jinfo mode allows one to see the targeted JVM's flags and system properties.

There are three main options used with jhsdb jinfo: --flags to see JVM flags, --sysprops to see the system properties, or no argument to see both the flags and the system properties. The next two screen snapshots demonstrate use of jhsdb jinfo --flags and jhsdb jinfo --sysprops. Running jhsdb jinfo without any arguments shows the system properties first followed by the flags, but is not shown here.

jhsdb "jsnap" Mode

The jhsdb mode jsnap provides access to information previously provided by the internal class sun.jvm.hotspot.tools.JSnap which was previously available in lib/sa-jdi.jar and which has been added to jhdsdb for JDK 9. There are two options for output from jhsdb jsnap based on whether no mode-specific argument is provided or if the --all mode-specific argument is provided. The next two screen snapshots demonstrate these two options.

These screenshots demonstrate that jhsdb jsnap with no mode-specific option lists information such as events related to threads and class loading/unloading along with core JVM properties. Adding the --all option lists these same properties, but in addition adds far more properties and, according to the documentation, "Prints all performance counters."

By the way, Marcus Hirt's Using the JVM Performance Counters provides an interesting look at how to apply JMX and custom MBeans to achieve a tool "similar to the PerformanceCounters MBean available in JRockit." I believe that jhsdb jsnap --all brings simple ability to see the same type of information in HotSpot as Hirt talked about being available in JRockit with jrcmd -l.

jhsdb Debug Modes

The three jhsdb modes hsdb (graphical user interface for interactive debugging), clhsdb (command-line interface for interactive debugging), and debugd (remote debug server) are related to debug operations. I may take a closer look at these modes in a future post, but for now I simply show some screen snapshots that demonstrate the graphical interaction using jhsdb hsdb. The GUI was started with jhsdb hsdb --pid <pid> and most of the options displayed here were run by selecting the specific menu option under "Tools".

As can be seen in the article HotSpot's Hidden Treasure, the serviceability debugger GUI has been available before JDK 9 and jhsdb, but this article also shows how much more difficult it was to find and start this tool before JDK 9's introduction of jhsdb.

Relationship of jhsdb to jcmd and to Other Command-line JDK Tools

I summarized the relationship of general-purpose tool jcmd to other JDK-provided command-line tools in the blog post jcmd: One JDK Command-Line Tool to Rule Them All. I adapt that table here to add jhsdb to the mix.

FunctionalityjhsdbjcmdSimilar Tool
Listing Java Processes N/A1 jcmd jps -lm
Heap Dumps jhsdb jmap --binaryheap jcmd <pid> GC.heap_dump jmap -dump <pid>
Heap Usage Histogram jhsdb jmap --histo jcmd <pid> GC.class_histogram jmap -histo <pid>
Thread Dump jhsdb jstack --locks
(subset of locked thread frames)
jcmd <pid> Thread.print jstack <pid>
List System Properties jhsdb jinfo --sysprops jcmd <pid> VM.system_properties jinfo -sysprops <pid>
List VM Flags jhsdb jinfo --flags jcmd <pid> VM.flags jinfo -flags <pid>

1 You use jcmd or jps -lm to identify PID upon which to have jhsdb, jcmd, and many other tools act if working against a running JVM. I used jcmd in this post to identify the PID, but the current jhsdb documentation demonstrates using jps to acquire the JVM PID.

The jhsdb tool is a mostly command-line tool that does also have an optional interactive GUI available that supports reporting of many of the commonly desired attributes of a JVM that is hung or has crashed. It provides a consistent interface across its modes and the command-line interaction allows for interactive help requests such that very little syntax must be known or remembered before applying the tool. If one can remember "jhsdb", one can start using the tool effectively. The jhsdb tool is new to JDK 9, but brings functionality into one tool that was previously available from several different tools.

Wednesday, May 17, 2017

Kotlin and Android: JetBrains and Google Behind One Language

Google I/O 2017 had several major announcements, but one of the most interesting to me is "first-class support for Kotlin" on Android.

The Kotlin blog post on this announcement discusses the benefits this brings to Kotlin users:

In case you are concerned about other platforms that Kotlin supports (Kotlin/JVM for server and desktop, Kotlin/JS and Kotlin/Native), please be sure that they are as important for us as ever. Our vision here is to make Kotlin a uniform tool for end-to-end development of various applications bridging multiple platforms with the same language. ... First-class support on Android will likely bring more users to Kotlin, and we expect the community to grow significantly. This means more libraries and tools developed in/for Kotlin, more experience shared, more Kotlin job offerings, more learning materials published, and so on. We are excited to see the Kotlin ecosystem flourish!

An interesting point related to and included in this announcement is mentioned in the Kotlin on Android FAQ:

What's the future of Kotlin? JetBrains' thoughtful work on Kotlin's design is one of the reasons we're embracing the language. Google is partnering with JetBrains to ensure a wonderful overall developer story—from language, to framework, to tools. And, we are excited to be working together to move the Kotlin language into a non profit foundation.

The Kotlin blog post describes the future of Kotlin with Android in greater detail:

We will be partnering with Google to create a non-profit foundation for Kotlin. Language development will continue to be sponsored by JetBrains, and the Kotlin team (over 40 people and second largest team at the company) will operate as usual. Andrey Breslav remains the Lead Language Designer, and Kotlin will be developed under the same principles as before.

Android 3.0 Canary 1 (preview) can currently be downloaded at https://developer.android.com/studio/preview/index.html at includes Kotlin support among its new features that include Java 8 support.

In the 2016 edition of my annual post on significant software developments of the year, I listed Kotlin-related developments in the "Honorable Mention" section. With this announcement of Kotlin being officially supported on Android and the language being placed in nonprofit foundation and enjoying support of Google and JetBrains, I think it's very possible that Kotlin will make my top ten list in 2017 for significant software language development developments. Besides these announcements, Kotlin has already seen JavaScript support released in Kotlin 1.1 in 2017 and a preview of Kotlin/Native.

Monday, May 15, 2017

JVM Statistics with jstat

I have written about several command-line tools provided with the Oracle and/or OpenJDK Java Development Kits (JDKs) in the past, but I've never written exclusively about the jstat tool. The Oracle JDK 9 Documentation Early Access states that jstat is used "to monitor Java Virtual Machine (JVM) statistics." There is also a warning, "This command is experimental and unsupported." Although I quoted the JDK 9 documentation, jstat has been a part of the Sun/Oracle JDK in some form (known at one time as jvmstat) in Java SE 8, Java SE 7, Java SE 6, and J2SE 5. Instrumentation for the HotSpot JVM was introduced with Java 1.4.1 (only enabled when -XX:+UsePerfData was set) and has provided "always-on instrumentation" since Java 1.4.2.

Much of the information that jstat provides can be gleaned from visual tools such as VisualVM, JMX and platform MBeans, garbage collection logs or via JVM options. However, jstat provides advantages when compared to each of these alternatives. Its advantages include those common to command-line tools such as the ability to execute from scripts and run without need of developers or others being present. It also is useful to be able to apply jstat to an already running Java process to start monitoring its JVM statistics rather than having the specify the monitoring of those options when starting the JVM.

For my examples in this post, I am using Oracle JDK 9 build 164. The next screen snapshot shows this version and also shows one of the first flags to apply when starting to use jstat: the -options flag.

As demonstrated in the screen snapshot, and as stated in the jstat documentation, jstat -options is used to "display the list of options for a particular platform installation." In my example being shown here, the following options are available:

  • -class
  • -compiler
  • -gc
  • -gccapacity
  • -gccause
  • -gcmetacapacity
  • -gcnew
  • -gcnewcapacity
  • -gcold
  • -gcoldcapacity
  • -gcutil
  • -printcompilation

I'll only be looking at a small subset of these available options in this post, but the jstat documentation provides a single sentence describing each jstat option and the command-line use of each option is very similar to all other options. In fact, once one learns a few minor things regarding use of jstat, the execution of various options becomes the easy part. The difficult part of using jstat is often interpreting the data provided by jstat.

The jstat -help option prints a simple usage as shown in the next screen snapshot.

From the jstat usage message, we learn that the jstat command-line tool is executed by running the name of the command first (jstat) with the hyphenated option name next, followed by the optional -t and/or -h flags, followed by a vimid, and concluding with an optional interval and optional count of the number of times to execute the command on the provided interval. Examples are clearer than descriptive text and some examples are shown in this post and in the jstat documentation.

For monitoring "local" JVM statistics, the vmid is simply the process ID of the JVM process. This is the same PID returned by the hip jcmd (or stodgy jps) for Java processes. The next screen snapshot demonstrates use of jcmd to identify the PID (8728 in this case) of the Java application I'm monitoring in my examples (JEdit in this case).

The "Virtual Machine Identifier" section of the jstat documentation provides significantly more details regarding the vmid because a more complicated vmid (for remote monitoring of JVM statistics) can include a protocol, the local targeted machine's vmid, host, and port. Although all of my examples in this post will use jstat and a simple Java PID (vmid), the jstat documentation does provide examples of use of a more detailed vmid for remote monitoring of JVM statistics.

For the remaining examples in this post, I wanted a Java application that was a bit more interesting from a JVM statistics monitoring perspective than JEdit is. I decided to use the "PigInThePython" sample application from Nikita Salnikov-Tarnovski's post "Garbage Collection: increasing the throughput" on the highly recommended Plumbr Blog. See that post if you're interested in seeing the source code for PigInThePython.

For my first example of using jstat, I use one of its most commonly used options: -gcutil. Besides demonstrating the -gcutil option, I'll use this first example to also demonstrate and explain the jstat output options that generally apply to other jstat options besides gcutil.

The following screen snapshot demonstrates use of jcmd to acquire the PID of the PigInThePython application (5096 in this case) and running of the simplest form of jstat -gcutil.

In its simplest form (with no other options), jstat -gcutil displays a single line of output with no timestamp. The column headings are described in the jstat documentation section "-gcutil option" which also describes the -gcutil option as, "Summary of garbage collection statistics." This documentation explains, for example, that several of the columns indicate percentages of usage of different spaces' allocations while other columns indicate number of garbage collection events and total garbage collection time.

We often want to associate the statistics that jstat provides with the time that other events are occurring in the monitored system to identify correlations between those events and effects on the JVM. The jstat -t option will prepend a timestamp at the beginning of the output. This timestamp is the number of seconds since the JVM that is being monitored was started. Although this is not as convenient for humans to read as other formats, it does make it possible to correlate the JVM statistics with timeframes in which the JVM has been running and with garbage collection logs that had time stamps included. The next screen snapshot demonstrates -t in action:

It is typically useful to monitor JVM statistics such as those presented by jstat -gcutil more than once. The next screen snapshot demonstrates use of a specified interval (100 milliseconds intervals as specified with 100ms to have these results captured and shown every 100 milliseconds.

The output in the last screen snapshot never repeats the header with the column acronyms after showing it the first time. If one wants to have that header repeated after a certain number of lines to make it easier to know which numbers belong with which columns much farther down in the output, the -h option can be used to specify the number of results after which the column headers are displayed again. In the next screen snapshot, -h20 is used to see the header after every 20 rows.

There may be times when it's desirable to have jstat provide its data every so often and only for a certain number of times. The interval allows one to specify the duration of time between the results and any integer following that interval specification acts as the limit on the total number of times the results will be displayed. In the next screen snapshot, the 15 at the end of the command limits the output to 15 total rows.

The jstat -gccause option returns the same information as -gcutil, but also adds information about what caused the monitored garbage collections. The following screen snapshot demonstrates this.

In the above screen snapshot, we see that the "cause of last garbage collection" (LGCC) was "G1 Humongous Allocation" and that "cause of current garbage collection" (GCC) is "No GC" (there is no garbage collection currently underway).

The next screen snapshot demonstrates use of jstat -class to see "Class loader statistics" number of classes loaded ("Loaded"), number of kilobytes loaded (first "Bytes"), number of classes unloaded ("Unloaded"), and number of kilobytes unloaded (second "Bytes"), and "time spent performing class loading and unloading operations" ("Time").

The command jstat -printcompilation indicates "Java HotSpot VM compiler method statistics" and is demonstrated in the next screen snapshot.

The -printcompilation option displays columns "Compiled" ("Number of compilation tasks performed by the most recently compiled method"), "Size" ("Number of bytes of byte code of the most recently compiled method"), "Type" ("Compilation type of the most recently compiled method"), and "Method" (name of class/method of most recently compiled method expressed in format consistent with HotSpot VM option -XX:+PrintCompilation).

The jstat -compiler command allows us to see "Java HotSpot VM Just-in-Time compiler statistics" such as number of compilation tasks performed ("Compiled"), number of failed compilation tasks ("Failed"), number of invalidated compilation tasks ("Invalid"), time spent on compilation ("Time"), type and class/method name of last failed compilation ("FailedType" and "FailedMethod"). This is demonstrated in the next screen snapshot.

There are several more options available with jstat and most of them are specific to different perspectives on garbage collection in the monitored JVM.

The jstat documentation warns that the tool is experimental and subject to change or removal in future versions of the JDK. The documentation also warns against writing scripts and tools that parse the output of jstat as the output content or format might change in the future. However, I can see how some might take the risk and write parsing code because this command-line tool is easily accessible from scripts and the parsing code needed would not be very complex.

This post has been an introduction to jstat, but there is much more to learn about the tool. Interpretation of the tool's results is more complex than using the tool and the analysis of the data provided by jstat is likely to be more challenging than the effort to collect the numbers. Several additional resources are listed below to provide more information on the collecting of and analyzing of Java Virtual Machine statistics with the jstat tool.

Additional jstat Resources

Wednesday, May 10, 2017

Java Platform Module System Public Review Fails to Pass

There has been an unusual level of drama, intrigue, and politics in the world of Java over the past few weeks that culminated in this week's JSR 376 Java Platform Module System Public Review Ballot. Java modularity [including the Java Platform Module System (JPMS)] has been arguably the most significant piece of JDK 9 and so it's not surprising that it has received so much attention. In addition to the typical publicly available mailing list traffic, there have been blog posts and open letters to further advertise the contention and debate surrounding JPMS (JSR 376), described as "a central component of Project Jigsaw."

The final vote was, according to the JSR #376 Java Platform Module System Public Review Ballot page, 10 votes for and 13 votes against, so "the EC has not approved this ballot." The comments that go along with the votes in the text area at the bottom of the ballot page are telling. In particular, I thought it interesting how many reviewers vote no mainly because they were uncomfortable with the other, more vocal reviewers not approving. It's also interesting that the Public Review Ballot for JSR #379 Java SE 9 Release Contents (an "umbrella" JSR) passed overwhelmingly on the same day this one failed.

It will be interesting to see how this continues to unfold over the coming days and weeks and what impact is has on the release date for JDK 9. Rather than rehash the arguments on both sides, I reference posts from key contributors to the discussion below.

References: Executive Committee Participants/Representatives

References: Opinions/Forums

References: Other Overviews

References: Since the Vote

Since the Vote: Java Platform Module System (JSR 376) EG minutes