1. Operating System Access

Java developers often don’t realize how much the Java libraries abstract from the operating system. A few examples: Java automatically sets the correct path separator (/ or \) for path entries, and automatically sets the operating system’s usual end-of-line character for line breaks. When formatting for console input and when parsing console input, Java automatically falls back on the set language of the operating system.

Not only does the Java library use these properties internally, but they are accessible to all. The properties are hidden in various places, such as:

  • in system properties

  • in platform MXBeans, like the OperatingSystemMXBean you get with getSystemCpuLoad()

  • in java.net.NetworkInterface for network cards and MAC address

  • in Toolkit for screen resolution

  • in GraphicsEnvironment for the installed fonts

If special information is missing, Java programs can call external native programs and interact with them, for example, to ask for more details. The tasks in this chapter focus on system properties and how to call external programs.

Prerequisites

  • know how to interact with the command line

  • be able to evaluate environment variables

  • be able to start external programs

Data types used in this chapter:

1.1. Console

Java programs are not just algorithms, they interact with us and with the operating system. Two of the first statements were System.out.println() and new Scanner(System.in).next() — a screen output and console input are typical interfaces between program and user.

System.out and System.err are of type PrintStream, System.in is of type InputStream. The class System has methods to redirect the three streams, for example into files.

1.1.1. Colored console outputs ⭐

Even in the very earliest Java programs, we output text on the console. However, the text output on System.out and System.err shows the text once in black, then in red, so there are different colors.

In this task, we want to deal with the question of how we can write colored outputs ourselves. The solution behind this is that outputs write more than just text. There are special commands that change the color in the console, move the cursor, clear the screen, and so on. This is done by ANSI escape sequences; they start with a control sequence introducer, the string

\u001B[

and they end with the string

m

\u001B is the ESC character in the ASCII alphabet, decimal 27.

In Java, escape sequences can easily be written to System.out or System.err, and there are libraries such as https://github.com/fusesource/jansi that simplify this via constants and methods. The only problem is that the different consoles do not necessarily recognize all escape sequences. By default, Windows' cmd.exe, for example, is unable to recognize any of them. However, support for some colors is common on other consoles:

  • Black: \u001B[30m

  • Red: \u001B[31m

  • Green: \u001B[32m

  • Yellow: \u001B[33m

  • Blue: \u001B[34m

  • Magenta: \u001B[35m

  • Cyan: \u001B[36m

  • White: \u001B[37m

  • Reset: \u001B[0m

Suitable for decoration:

  • bold: \u001B[1m

  • underlined: \u001B[4m

  • inverted: \u001B[7m

Task:

  • Create a new class AnsiColorHexDumper, and put the following constants in the class:

    public static final String ANSI_RED    = "\u001B[31m";
    public static final String ANSI_GREEN  = "\u001B[32m";
    public static final String ANSI_BLUE   = "\u001B[34m";
    public static final String ANSI_PURPLE = "\u001B[35m";
    public static final String ANSI_CYAN   = "\u001B[36m";
    public static final String ANSI_RESET  = "\u001B[0m";
  • Write a new method printColorfulHexDump(Path) that reads the given file and prints it as a hexd ump on the console. A hex dump is the output of a file in hexadecimal notation, i.e., sequences like 50 4B 03 04 14 00 06 00 08 00 written in columns.

  • Extend the program so that colors indicate the occurrence of certain bytes in the file. For example, ASCII letters can appear in one color, but digits in another.

1.2. Properties

The term properties is used multiple times in Java. It stands for the JavaBean properties and for key-value pairs that can be used for configuration. When we talk about "properties" in this chapter, we always mean key-value pairs, especially the pairs that a Properties object manages.

1.2.1. Windows or Unix or macOS? ⭐

The system properties contain a set of information, some of which is accessible via methods. The Javadoc lists the variables at https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getProperties--.

Task:

  • Create a new enumeration type OS with the constants WINDOWS, MACOS, UNIX, UNKNOWN.

  • Add a static method current() which reads the name of the operating system with System.getProperty("os.name") and returns the corresponding enumeration element as result.

1.2.2. Unify command line properties and properties from files ⭐

Properties can be set from the command line and can thus be introduced into a Java program from the outside.

Web servers run on different ports, usually 8080 in development mode.

Task:

  • Write a program that can accept port information from different sources:

    • On the command line, the port can be specified with --port=8000.

    • If --port does not exist, an environment variable port should be evaluated, which can also be set on the command line with -Dport=8020.

    • If the environment variable does not exist, an assignment like port=8888 is to be evaluated in an application.properties file.

    • If no specification is made at all, the port is set to 8080 by default.

  • Finally, output the port.

Example for three call variants:

$ java com.tutego.exercise.os.PortConfiguration
$ java com.tutego.exercise.os.PortConfiguration --port=8000
$ java -Dport=8020 com.tutego.exercise.os.PortConfiguration

1.3. Execute external processes

As a platform-independent programming language, Java cannot offer everything, and so there are several ways to make requests to the host environment, to the operating system. One simple way is to call external programs, which is what is asked for in the next task.

1.3.1. Read the battery status via Windows Management Instrumentation ⭐⭐

Bonny Brain is playing a strategy game in her notebook. The next round will take 30 minutes, and since her notebook runs on battery power only, she wants to avoid having to abort the game if the battery is about to die. The following calls can be used on the command line on Windows to determine the percentage of runtime remaining and the number of minutes remaining estimated by that of the current load:

> wmic path win32_battery get EstimatedChargeRemaining
EstimatedChargeRemaining
10

> wmic path win32_battery get EstimatedRunTime
EstimatedRunTime
37

If the computer is not a laptop with a battery, the output is "No instances available." If the laptop is loaded, the result for EstimatedRunTime is 71582788 (hexadecimal 4444444). Microsoft provides details at https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-battery.

Task:

  • In a Java program, start the Windows program wmic as an external process using ProcessBuilder. Read the result of EstimatedChargeRemaining and EstimatedRunTime.

  • Consider that a laptop can be powered from the power grid or a desktop computer has no battery.

Microsoft’s operating system provides an API named Windows Management Instrumentation (WMI) that can be used to read and, in some cases, change settings on a computer. WMI is comparable to JMX on the Java side. Because shell scripts often want to access this mapping for automation purposes, Microsoft has created a command-line interface Windows Management Instrumentation Command-line (WMIC).

A WMI provider provides information about CPU usage, motherboard, network, battery status, and much more. The following call gives a small overview:

> wmic /?