Section 5.17. Miscellaneous Platform Features

5.17. Miscellaneous Platform Features

The following sections detail important but miscellaneous features of the Java platform, including properties, preferences, processes, and management and instrumentation.

5.17.1. Properties

java.util.Properties is a subclass of java.util.Hashtable , a legacy collections class that predates the Collections API introduced in Java 1.2. A Properties object maintains a mapping between string keys and string values and defines methods that allow the mappings to be written to and read from a simple text file or (in Java 5.0) an XML file. This makes the Properties class ideal for configuration and user preference files. The Properties class is also used for the system properties returned by System.getProperty( ) :

 import java.util.*; import java.io.*; // Note: many of these system properties calls throw a security exception if // called from untrusted code such as applets. String homedir = System.getProperty("user.home"); // Get a system property Properties sysprops = System.getProperties();     // Get all system properties // Print the names of all defined system properties for(Enumeration e = sysprops.propertyNames(); e.hasMoreElements();)    System.out.println(e.nextElement()); sysprops.list(System.out); // Here's an even easier way to list the properties // Read properties from a configuration file Properties options = new Properties();             // Empty properties list File configfile = new File(homedir, ".config");    // The configuration file try {   options.load(new FileInputStream(configfile));   // Load props from the file } catch (IOException e) { /* Handle exception here */ } // Query a property ("color"), specifying a default ("gray") if undefined String color = options.getProperty("color", "gray");   // Set a property named "color" to the value "green" options.setProperty("color", "green");   // Store the contents of the Properties object back into a file try {   options.store(new FileOutputStream(configfile),  // Output stream                 "MyApp Config File");              // File header comment text } catch (IOException e) { /* Handle exception */ } // In Java 5.0 properties can be written to or read from XML files try {   options.storeToXML(new FileOutputStream(configfile),  // Output stream                      "MyApp Config File");              // Comment text   options.loadFromXML(new FileInputStream(configfile)); // Read it back in } catch(IOException e) { /* Handle exception */ } catch(InvalidPropertiesFormatException e) { /* malformed input */ } 

5.17.2. Preferences

Java 1.4 introduced the Preferences API, which is specifically tailored for working with user and systemwide preferences and is more useful than Properties for this purpose. The Preferences API is defined by the java.util.prefs package. The key class in that package is Preferences . You can obtain a Preferences object that contains user-specific preferences with the static method Preferences.userNodeForPackage() and obtain a Preferences object that contains systemwide preferences with Preferences.systemNodeForPackage() . Both methods take a java.lang.Class object as their sole argument and return a Preferences object shared by all classes in that package. (This means that the preference names you use must be unique within the package.) Once you have a Preferences object, use the get( ) method to query the string value of a named preference, or use other type-specific methods such as getInt( ) , getBoolean() , and getByteArray() . Note that to query preference values, a default value must be passed for all methods. This default value is returned if no preference with the specified name has been registered or if the file or database that holds the preference data cannot be accessed. A typical use of Preferences is the following:

 package com.davidflanagan.editor; import java.util.prefs.Preferences; public class TextEditor {   // Fields to be initialized from preference values   public int width;             // Screen width in columns   public String dictionary;     // Dictionary name for spell checking   public void initPrefs() {     // Get Preferences objects for user and system preferences for this package     Preferences userprefs = Preferences.userNodeForPackage(TextEditor.class);     Preferences sysprefs = Preferences.systemNodeForPackage(TextEditor.class);     // Look up preference values. Note that you always pass a default value.     width = userprefs.getInt("width", 80);     // Look up a user preference using a system preference as the default     dictionary = userprefs.get("dictionary",                                sysprefs.get("dictionary",                                             "default_dictionary"));   } } 

In addition to the get( ) methods for querying preference values, there are corresponding put() methods for setting the values of named preferences:

 // User has indicated a new preference, so store it userprefs.putBoolean("autosave", false); 

If your application wants to be notified of user or system preference changes while the application is in progress, it may register a PreferenceChangeListener with addPreferenceChangeListener() . A Preferences object can export the names and values of its preferences as an XML file and can read preferences from such an XML file. (See importPreferences( ) , exportNode() , and exportSubtree( ) in java.util.pref.Preferences in the reference section.) Preferences objects exist in a hierarchy that typically corresponds to the hierarchy of package names. Methods for navigating this hierarchy exist but are not typically used by ordinary applications.

5.17.3. Processes

Earlier in the chapter, we saw how easy it is to create and manipulate multiple threads of execution running within the same Java interpreter. Java also has a java.lang.Process class that represents an operating system process running externally to the interpreter. A Java program can communicate with an external process using streams in the same way that it might communicate with a server running on some other computer on the network. Using a Process is always platform-dependent and is rarely portable, but it is sometimes a useful thing to do:

 // Maximize portability by looking up the name of the command to execute // in a configuration file.  java.util.Properties config;   String cmd = config.getProperty("sysloadcmd"); if (cmd != null) {   // Execute the command; Process p represents the running command   Process p = Runtime.getRuntime().exec(cmd);         // Start the command   InputStream pin = p.getInputStream();               // Read bytes from it   InputStreamReader cin = new InputStreamReader(pin); // Convert them to chars   BufferedReader in = new BufferedReader(cin);        // Read lines of chars   String load = in.readLine();                        // Get the command output   in.close();                                         // Close the stream } 

In Java 5.0 the java.lang.ProcessBuilder class provides a more flexible way to launch new processes than the Runtime.exec() method. ProcessBuilder allows control of environment variables through a Map and makes it simple to set the working directory. It also has an option to automatically redirect the standard error stream of the processes it launches to the standard output stream, which makes it much easier to read all output of a Process .

 import java.util.Map; import java.io.* public class JavaShell {     public static void main(String[] args) {         // We use this to start commands         ProcessBuilder launcher = new ProcessBuilder();         // Our inherited environment vars.  We may modify these below         Map<String,String> environment = launcher.environment();         // Our processes will merge error stream with standard output stream         launcher.redirectErrorStream(true);         // Where we read the user's input from         BufferedReader console =             new BufferedReader(new InputStreamReader(System.in));         while(true) {             try {                 System.out.print("> ");               // display prompt                 System.out.flush();                   // force it to show                 String command = console.readLine();  // Read input                 if (command.equals("exit")) return;   // Exit command                 else if (command.startsWith("cd ")) { // change directory                     launcher.directory(new File(command.substring(3)));                 }                 else if (command.startsWith("set ")) {// set environment var                     command = command.substring(4);                     int pos = command.indexOf('=');                     String name = command.substring(0,pos).trim();                     String var = command.substring(pos+1).trim();                     environment.put(name, var);                 }                                      else { // Otherwise it is a process to launch                     // Break command into individual tokens                     String[] words = command.split(" ");                     launcher.command(words);      // Set the command                     Process p = launcher.start(); // And launch a new process                     // Now read and display output from the process                      // until there is no more output to read                     BufferedReader output = new BufferedReader(                              new InputStreamReader(p.getInputStream()));                     String line;                     while((line = output.readLine()) != null)                          System.out.println(line);                                                           // The process should be done now, but wait to be sure.                     p.waitFor();                 }             }             catch(Exception e) {                 System.out.println(e);             }         }     } } 

5.17.4. Management and Instrumentation

Java 5.0 includes the powerful JMX API for remote monitoring and management of running applications. The full javax.management API is beyond the scope of this book. The reference section does cover the java.lang.management package, however: this package is an application of JMX for the monitoring and management of the Java virtual machine itself. java.lang.instrument is another Java 5.0 package: it allows the definition of " agents " that can be used to instrument the running JVM. In VMs that support it, java.lang.instrument can be used to redefine class files as they are loaded to add profiling or coverage testing code, for example. Class redefinition is beyond the scope of this chapter, but the following code uses the new instrumentation and management features of Java 5.0 to determine resource usages of a Java program. The example also demonstrates the Runtime.addShutdownHook() method, which registers code to be run when the VM starts shutting down.

 import java.lang.instrument.*; import java.lang.management.*; import java.util.List; import java.io.*; public class ResourceUsageAgent {     // A Java agent class defines a premain() method to run before main()     public static void premain(final String args, final Instrumentation inst) {        // This agent simply registers a shutdown hook to run when the VM exits         Runtime.getRuntime().addShutdownHook(new Thread() {                 public void run() {                     // This code runs when the VM exits                     try {                         // Decide where to send our output                         PrintWriter out;                         if (args != null && args.length() > 0)                              out = new PrintWriter(new FileWriter(args));                         else                             out = new PrintWriter(System.err);                         // Use java.lang.management to query peak thread usage                         ThreadMXBean tb = ManagementFactory.getThreadMXBean();                         out.printf("Current thread count: %d%n",                                    tb.getThreadCount());                         out.printf("Peak thread count: %d%n",                                    tb.getPeakThreadCount());                         // Use java.lang.management to query peak memory usage                         List<MemoryPoolMXBean> pools =                              ManagementFactory.getMemoryPoolMXBeans();                         for(MemoryPoolMXBean pool: pools) {                             MemoryUsage peak = pool.getPeakUsage();                             out.printf("Peak %s memory used: %,d%n",                                        pool.getName(), peak.getUsed());                             out.printf("Peak %s memory reserved: %,d%n",                                        pool.getName(), peak.getCommitted());                         }                         // Use the Instrumentation object passed to premain()                         // to get a list of all classes that have been loaded                         Class[] loaded = inst.getAllLoadedClasses();                         out.println("Loaded classes:");                         for(Class c : loaded) out.println(c.getName());                         out.close();  // close and flush the output stream                     }                     catch(Throwable t) {                         // Exceptions in shutdown hooks are ignored so                         // we've got to print this out explicitly                         System.err.println("Exception in agent: " + t);                     }                 }             });     } } 

To monitor the resource usage of a Java program with this agent, you first must compile the class normally. You then store the generated class files in a JAR file with a manifest that specifies the class that contains the premain() method. Create a manifest file that contains this line:

 Premain-Class: ResourceUsageAgent 

Create the JAR file with a command like this:

 %  jar cmf manifest agent.jar ResourceUsageAgent*.class  

Finally, to use the agent, specify the JAR file and the agent arguments with the -javaagent flag to the Java interpreter:

 %  java -javaagent:agent.jar=/tmp/usage.info my.java.Program  



Java In A Nutshell
Java In A Nutshell, 5th Edition
ISBN: 0596007736
EAN: 2147483647
Year: 2004
Pages: 1220

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net