AN application runs in a platform environment, defined by the underlying operating system, the Java virtual machine, the class libraries, and various configuration data supplied when the application is launched. This chapter describes some of the APIs an application uses to examine and configure its platform environment.
This section describes some of the configuration utilities that help an application access its startup context.
Properties are configuration values managed as key/value pairs. In each pair, the key and value are both String
[1] values. The key identifies, and is used to retrieve, the value, much as a variable name is used to retrieve the variable’s value. For example, an application capable of downloading files might use a property named “download.lastDirectory” to keep track of the directory used for the last download.
To manage properties, create instances of java.util.Properties
.[2] This class provides methods for the following:
For an introduction to streams, refer to the I/O Streams section (page 261).
Properties
extends java.util.Hashtable
.[3] Some of the methods inherited from Hashtable
support the following actions:
testing to see if a particular key or value is in the Properties
object,
getting the current number of key/value pairs,
removing a key and its value,
adding a key/value pair to the Properties
list,
enumerating over the values or the keys,
retrieving a value by its key, and
finding out if the Properties
object is empty.
Access to properties is subject to approval by the current security manager. The example code segments in this section are assumed to be in standalone applications, which, by default, have no security manager. The same code in an applet may not work depending on the browser or viewer in which it is running. See docs/books/tutorial/deployment/applet/properties.html
for information about security restrictions on applets.
The System
class maintains a Properties
object that defines the configuration of the current working environment. For more about these properties, see the System Properties section (page 452). The remainder of this section explains how to use properties to manage application configuration.
Figure 14.1 illustrates how a typical application might manage its configuration data with a Properties
object over the course of its execution.
Starting Up. The actions given in the first three boxes occur when the application is starting up. First, the application loads the default properties from a well-known location into a Properties
object. Normally, the default properties are stored in a file on disk along with the .class
and other resource files for the application.
Next, the application creates another Properties
object and loads the properties that were saved from the last time the application was run. Many applications store properties on a per-user basis, so the properties loaded in this step are usually in a specific file in a particular directory maintained by this application in the user’s home directory. Finally, the application uses the default and remembered properties to initialize itself.
The key here is consistency. The application must always load and save properties to the same location so that it can find them the next time it’s executed.
Running. During the execution of the application, the user may change some settings, perhaps in a Preferences window, and the Properties
object is updated to reflect these changes. If the user’s changes are to be remembered in future sessions, they must be saved.
Exiting. Upon exiting, the application saves the properties to its well-known location, to be loaded again when the application is next started up.
The following Java code performs the first two steps described in the previous section—loading the default properties and loading the remembered properties:
... // create and load default properties Properties defaultProps = new Properties(); FileInputStream in = new FileInputStream("defaultProperties"); defaultProps.load(in); in.close(); // create application properties with default Properties applicationProps = new Properties(defaultProps); // now load properties from last invocation in = new FileInputStream("appProperties"); applicationProps.load(in); in.close(); ...
First, the application sets up a default Properties
object. This object contains the set of properties to use if values are not explicitly set elsewhere. Then the load method reads the default values from a file on disk named defaultProperties
.
Next, the application uses a different constructor to create a second Properties
object, applicationProps
, whose default values are contained in defaultProps
. The defaults come into play when a property is being retrieved. If the property can’t be found in applicationProps
, then its default list is searched.
Finally, the code loads a set of properties into applicationProps
from a file named appProperties
. The properties in this file are those that were saved from the application the last time it was invoked, as explained in the next section.
The following example writes out the application properties from the previous example using Properties.store
. The default properties don’t need to be saved each time because they never change:
FileOutputStream out = new FileOutputStream("appProperties"); applicationProps.store(out, "---No Comment---"); out.close();
The store
method needs a stream to write to, as well as a string that it uses as a comment at the top of the output.
Once the application has set up its Properties
object, the application can query the object for information about various keys and values that it contains. An application gets information from a Properties
object after start up so that it can initialize itself based on choices made by the user. The Properties
class has several methods for getting property information:
contains(Object value)containsKey(Object key)
Returns true
if the value or the key is in the Properties
object. Properties
inherits these methods from Hashtable
. Thus they accept Object
arguments, but only String
values should be used.
getProperty(String key)getProperty(String key, String default)
Returns the value for the specified property. The second version provides for a default value. If the key is not found, the default is returned.
list(PrintStream s)list(PrintWriter w)
Writes all of the properties to the specified stream or writer. This is useful for debugging.
elements()keys()propertyNames()
Returns an Enumeration
containing the keys or values (as indicated by the method name) contained in the Properties
object. The keys
method only returns the keys for the object itself; the propertyNames
method returns the keys for default properties as well.
stringPropertyNames()
Like propertyNames
, but returns a Set<String>
, and only returns names of properties where both key and value are strings. Note that the Set
object is not backed by the Properties
object, so changes in one do not affect the other.
size()
Returns the current number of key/value pairs.
A user’s interaction with an application during its execution may impact property settings. These changes should be reflected in the Properties
object so that they are saved when the application exits (and calls the store
method). The following methods change the properties in a Properties
object:
Some of the methods just described are defined in Hashtable
, and thus accept key and value argument types other than String
. Always use String
s for keys and values, even if the method allows other types. Also, do not invoke Hashtable.set
or Hastable.setAll
on Properties
objects; always use Properties.setProperty
.
A Java application can accept any number of arguments from the command line. This allows the user to specify configuration information when the application is launched.
The user enters command-line arguments when invoking the application and specifies them after the name of the class to be run. For example, suppose a Java application called Sort
sorts lines in a file. To sort the data in a file named friends.txt
, a user would enter:
java Sort friends.txt
When an application is launched, the runtime system passes the command-line arguments to the application’s main method via an array of String
s. In the previous example, the command-line arguments passed to the Sort
application in an array that contains a single String
: "friends.txt"
.
The Echo
[4] example displays each of its command-line arguments on a line by itself:
public class Echo { public static void main (String[] args) { for (String s: args) { System.out.println(s); } } }
The following example shows how a user might run Echo
. User input is in italics:
java Echo Drink Hot Java
Drink
Hot
Java
Note that the application displays each word—Drink
, Hot
, and Java
—on a line by itself. This is because the space character separates command-line arguments. To have Drink
, Hot
, and Java
interpreted as a single argument, the user would join them by enclosing them within quotation marks:
java Echo "Drink Hot Java"
Drink Hot Java
If an application needs to support a numeric command-line argument, it must convert a String
argument that represents a number, such as “34”, to a numeric value. Here is a code snippet that converts a command-line argument to an int
:
int firstArg; if (args.length > 0) { try { firstArg = Integer.parseInt(args[0]); } catch (NumberFormatException e) { System.err.println("Argument must be an integer"); System.exit(1); } }
parseInt
throws a NumberFormatException
if the format of args[0]
isn’t valid. All of the Number
classes—Integer
, Float
, Double
, and so on—have parseXXX
methods that convert a String
representing a number to an object of their type.
Many operating systems use environment variables to pass configuration information to applications. Like properties in the Java platform, environment variables are key/value pairs, where both the key and the value are strings. The conventions for setting and using environment variables vary between operating systems, and also between command line interpreters. To learn how to pass environment variables to applications on your system, refer to your system documentation.
On the Java platform, an application uses System.getEnv
to retrieve environment variable values. Without an argument, getEnv
returns a read-only instance of java.util.Map
, where the map keys are the environment variable names, and the map values are the environment variable values. This is demonstrated in the EnvMap
[5] example:
import java.util.Map; public class EnvMap { public static void main (String[] args) { Map<String, String> env = System.getenv(); for (String envName : env.keySet()) { System.out.format("%s=%s%n", envName, env.get(envName)); } } }
With a String
argument, getEnv
returns the value of the specified variable. If the variable is not defined, getEnv
returns null
. The Env
[6] example uses getEnv
this way to query specific environment variables, specified on the command line:
public class Env { public static void main (String[] args) { for (String env: args) { String value = System.getenv(env); if (value != null) { System.out.format("%s=%s%n", env, value); } else { System.out.format("%s is not assigned.%n", env); } } } }
When a Java application uses a ProcessBuilder
[7] object to create a new process, the default set of environment variables passed to the new process is the same set provided to the application’s virtual machine process. The application can change this set using ProcessBuilder.environment
.
There are many subtle differences between the way environment variables are implemented on different systems. For example, Windows ignores case in environment variable names, while UNIX does not. The way environment variables are used also varies. For example, Windows provides the user name in an environment variable called USERNAME
, while UNIX implementations might provide the user name in USER
, LOGNAME
, or both.
To maximize portability, never refer to an environment variable when the same value is available in a system property. For example, if the operating system provides a user name, it will always be available in the system property user.name
.
Here is a summary of some other configuration utilities.
The Preferences API allows applications to store and retrieve configuration data in an implementation-dependent backing store. Asynchronous updates are supported, and the same set of preferences can be safely updated by multiple threads and even multiple applications. For more information, refer to the Preferences API Guide.[8]
An application deployed in a JAR archive uses a manifest to describe the contents of the archive. For more information, refer to Chapter 16.
The configuration of a Java Web Start application is contained in a JNLP file. For more information, refer to Chapter 17.
The configuration of a Java Plug-in applet is partially determined by the HTML tags used to embed the applet in the Web page. Depending on the applet and the browser, these tags can include <applet>
, <object>
, <embed>
, and <param>
. For more information, refer to Chapter 18.
The class java.util.ServiceLoader
[9] provides a simple service provider facility. A service provider is an implementation of a service—a well-known set of interfaces and (usually abstract) classes. The classes in a service provider typically implement the interfaces and subclass the classes defined in the service. Service providers can be installed as extensions (see docs/books/tutorial/ext/index.html
on the CD). Providers can also be made available by adding them to the class path or by some other platform-specific means.
The System
[10] class implements a number of system utilities. Some of these have already been covered in the Configuration Utilities section (page 443). This section covers some of the other system utilities.
System
provides several predefined I/O objects that are useful in a Java application that is meant to be launched from the command line. These implement the Standard I/O streams provided by most operating systems and also a console object that is useful for entering passwords. For more information, refer to the I/O from the Command Line section (page 276) in Chapter 10.
In the Properties section (page 443), we examined the way an application can use Properties
objects to maintain its configuration. The Java platform itself uses a Properties
object to maintain its own configuration. The System
class maintains a Properties
object that describes the configuration of the current working environment. System properties include information about the current user, the current version of the Java runtime, and the character used to separate components of a file path name.
Table 14.1 describes some of the most important system properties.
Table 14.1. Some Important System Properties
Key | Meaning |
---|---|
| Character that separates components of a file path. This is “ |
| Path used to find directories and JAR archives containing class files. Elements of the class path are separated by a platform-specific character specified in the |
| Installation directory for Java Runtime Environment (JRE) |
| JRE vendor name |
| JRE vender URL |
| JRE version number |
| Sequence used by operating system to separate lines in text files |
| Operating system architecture |
| Operating system name |
| Operating system version |
| Path separator character used in |
| User working directory |
| User home directory |
| User account name |
Access to system properties can be restricted by the security manager (page 455). This is most often an issue in applets, which are prevented from reading some system properties, and from writing any system properties. For more on accessing system properties in applets, refer to the Getting System Properties section (page 583).
The System
class has two methods used to read system properties: getProperty
and getProperties
.
The System
class has two different versions of getProperty
. Both retrieve the value of the property named in the argument list. The simpler of the two getProperty
methods takes a single argument, a property key. For example, to get the value of path.separator
, use the following statement:
System.getProperty("path.separator");
The getProperty
method returns a string containing the value of the property. If the property does not exist, this version of getProperty
returns null.
The other version of getProperty
requires two String
arguments: The first argument is the key to look up, and the second argument is a default value to return if the key cannot be found or if it has no value. For example, the following invocation of getProperty
looks up the System
property called subliminal.message
. This is not a valid system property, so instead of returning null, this method returns the default value provided as a second argument: “Buy StayPuft Marshmallows!
”:
System.getProperty("subliminal.message", "Buy StayPuft Marshmallows!");
The last method provided by the System
class to access property values is the getProperties
method, which returns a Properties
object. This object contains a complete set of system property definitions.
To modify the existing set of system properties, use System.setProperties
. This method takes a Properties
object that has been initialized to contain the properties to be set. This method replaces the entire set of system properties with the new set represented by the Properties
object.
Changing system properties is potentially dangerous and should be done with discretion. Many system properties are not reread after start-up and are there for informational purposes. Changing some properties may have unexpected side effects.
The next example, PropertiesTest
,[11] creates a Properties
object and initializes it from myProperties.txt
:
subliminal.message=Buy StayPuft Marshmallows!
PropertiesTest
then uses System.setProperties
to install the new Properties
objects as the current set of system properties:
import java.io.FileInputStream; import java.util.Properties; public class PropertiesTest { public static void main(String[] args) throws Exception { // set up new properties object // from file "myProperties.txt" FileInputStream propFile = new FileInputStream( "myProperties.txt"); Properties p = new Properties(System.getProperties()); p.load(propFile); // set the system properties System.setProperties(p); // display new properties System.getProperties().list(System.out); } }
Note how PropertiesTest
creates the Properties
object, p
, which is used as the argument to setProperties
:
Properties p = new Properties(System.getProperties());
This statement initializes the new properties object, p
, with the current set of system properties, which in the case of this small application is the set of properties initialized by the runtime system. Then the application loads additional properties into p
from the file myProperties.txt
and sets the system properties to p
. This has the effect of adding the properties listed in myProperties.txt
to the set of properties created by the runtime system at startup. Note that an application can create p
without any default Properties
object, like this:
Properties p = new Properties();
Also note that the value of system properties can be overwritten! For example, if myProperties.txt
contains the following line, the java.vendor
system property will be overwritten:
java.vendor=Acme Software Company
In general, be careful not to overwrite system properties.
The setProperties
method changes the set of system properties for the current running application. These changes are not persistent. That is, changing the system properties within an application will not affect future invocations of the Java interpreter for this or any other application. The runtime system re-initializes the system properties each time its starts up. If changes to system properties are to be persistent, then the application must write the values to some file before exiting and read them in again upon startup.
A security manager is an object that defines a security policy for an application. This policy specifies actions that are unsafe or sensitive. Any actions not allowed by the security policy cause a SecurityException
[12] to be thrown. An application can also query its security manager to discover which actions are allowed.
Typically, a Web applet runs with a security manager provided by the browser or Java Plug-in. Other kinds of applications normally run without a security manager, unless the application itself defines one. If no security manager is present, the application has no security policy and acts without restrictions.
This section explains how an application interacts with an existing security manager. For more detailed information, including information on how to design a security manager, refer to the Security Guide.[13]
The security manager is an object of type SecurityManager
;[14] to obtain a reference to this object, invoke System.getSecurityManager
:
SecurityManager appsm = System.getSecurityManager();
If there is no security manager, this method returns null
.
Once an application has a reference to the security manager object, it can request permission to do specific things. Many classes in the standard libraries do this. For example, System.exit
, which terminates the Java virtual machine with an exit status, invokes SecurityManager.checkExit
to ensure that the current thread has permission to shut down the application.
The SecurityManager
class defines many other methods used to verify other kinds of operations. For example, SecurityManager.checkAccess
verifies thread accesses, and SecurityManager.checkPropertyAccess
verifies access to the specified property. Each operation or group of operations has its own check
XXX
()
method.
In addition, the set of check
XXX
()
methods represents the set of operations that are already subject to the protection of the security manager. Typically, an application does not have to directly invoke any check
XXX
()
methods.
Many actions that are routine without a security manager can throw a SecurityException
when run with a security manager. This is true even when invoking a method that isn’t documented as throwing SecurityException
. For example, consider the following code used to read a file:
reader = new FileReader("xanadu.txt");
In the absence of a security manager, this statement executes without error, provided xanadu.txt
exists and is readable. But suppose this statement is inserted in a Web applet, which typically runs under a security manager that does not allow file input. The following error messages might result:
appletviewer fileApplet.html
Exception in thread "AWT-EventQueue-1"
java.security.AccessControlException: access denied
(java.io.FilePermission characteroutput.txt write)
...
Note that the specific exception thrown in this case, java.security.AccessControlException
,[15] is a subclass of SecurityException
.
This section describes some of the methods in System
that aren’t covered in the previous sections.
The arraycopy
method efficiently copies data between arrays. For more information, refer to the Arrays section (page 49).
The currentTimeMillis
and nanoTime
methods are useful for measuring time intervals during execution of an application. To measure a time interval in milliseconds, invoke currentTimeMillis
twice, at the beginning and end of the interval, and subtract the first value returned from the second. Similarly, invoking nanoTime
twice measures an interval in nanoseconds.
The accuracy of both currentTimeMillis
and nanoTime
is limited by the time services provided by the operating system. Do not assume that currentTimeMillis
is accurate to the nearest millisecond or that nanoTime
is accurate to the nearest nanosecond. Also, neither currentTimeMillis
nor nanoTime
should be used to determine the current time. Use a high-level method, such as java.util.Calendar.getInstance
.[16]
The exit
method causes the Java virtual machine to shut down, with an integer exit status specified by the argument. The exit status is available to the process that launched the application. By convention, an exit status of 0
indicates normal termination of the application, while any other value is an error code.
This section explains how to use the PATH
and CLASSPATH
environment variables on Microsoft Windows, Solaris, and Linux. Consult the installation instructions included with your installation of the Java Development Kit (JDK) software bundle for current information.
After installing the software, the JDK directory will have the structure shown in Figure 14.2. The bin
directory contains both the compiler and the launcher.
You can run Java applications just fine without setting the PATH
variable. Or, you can optionally set it as a convenience.
Set the PATH
variable if you want to be able to conveniently run the executables (javac.exe
, java.exe
, javadoc.exe
, and so on) from any directory without having to type the full path of the command. If you do not set the PATH
variable, you need to specify the full path to the executable every time you run it, such as:
C:Program FilesJavajdk1.6.0injavac MyClass.java
It is useful to set the PATH
permanently so it will persist after rebooting. To set it permanently, add the full path of the jdk1.6.0
bin directory to the PATH
variable. Set the PATH
as follows.
To make a permanent change to the CLASSPATH
variable, use the System icon in the Control Panel. The precise procedure varies depending on the version of Windows.
The PATH
can be a series of directories separated by semicolons (;
). Microsoft Windows looks for programs in the PATH
directories in order, from left to right. You should have only one bin
directory for the JDK in the path at a time (those following the first are ignored), so if one is already present you can update that particular entry.
You can run the JDK just fine without setting the PATH
variable, or you can optionally set it as a convenience. However, you should set the path variable if you want to be able to run the executables (javac
, java
, javadoc
, and so on) from any directory without having to type the full path of the command. If you do not set the PATH
variable, you need to specify the full path to the executable every time you run it, such as:
% /usr/local/jdk1.6.0/bin/javac MyClass.java
To find out if the path is properly set, execute:
% java -version
This will print the version of the java
tool, if it can find it. If the version is old or you get the error java: Command not found, then the path is not properly set.
To set the path permanently, set the path in your startup file.
For C shell (csh
), edit the startup file (~/.cshrc
):
set path=(/usr/local/jdk1.6.0/bin )
For bash
, edit the startup file (~/.bashrc
):
PATH=/usr/local/jdk1.6.0/bin: export PATH
For ksh
, the startup file is named by the environment variable, ENV
. To set the path:
PATH=/usr/local/jdk1.6.0/bin: export PATH
For sh
, edit the profile file (~/.profile
):
PATH=/usr/local/jdk1.6.0/bin: export PATH
Then load the startup file and verify that the path is set by repeating the java
command.
For C shell (csh
):
% source ~/.cshrc % java -version
For ksh
, bash
, or sh
:
% . /.profile % java -version
The CLASSPATH
variable is one way to tell applications, including the JDK tools, where to look for user classes. (Classes that are part of the JRE, JDK platform, and extensions should be defined through other means, such as the bootstrap class path or the extensions directory.)
The preferred way to specify the class path is by using the -cp
command line switch. This allows the CLASSPATH
to be set individually for each application without affecting other applications. Setting the CLASSPATH can be tricky and should be performed with care.
The default value of the class path is “.
”, meaning that only the current directory is searched. Specifying either the CLASSPATH
variable or the -cp
command line switch overrides this value.
To check whether CLASSPATH
is set on Microsoft Windows NT/2000/XP, execute the following:
C:> echo %CLASSPATH%
On Solaris or Linux, execute the following:
% echo $CLASSPATH
If CLASSPATH
is not set you will get a CLASSPATH: Undefined variable error (Solaris or Linux) or simply %CLASSPATH% (Microsoft Windows NT/2000/XP).
To modify the CLASSPATH
, use the same procedure you used for the PATH
variable.
Class path wildcards allow you to include an entire directory of .jar
files in the class path without explicitly naming them individually. For more information, including an explanation of class path wildcards and a detailed description on how to clean up the CLASSPATH
environment variable, see docs/books/tutorial/technotes/tools/windows/classpath.html
.
Write an application, PersistentEcho
, with the following features:
[1] docs/api/java/lang/String.html
[2] docs/api/java/util/Properties.html
[3] docs/api/java/util/Hashtable.html
[4] tutorial/essential/environment/examples/Echo.java
[5] tutorial/essential/environment/examples/EnvMap.java
[6] tutorial/essential/environment/examples/Env.java
[7] docs/api/java/lang/ProcessBuilder.html
[8] docs/guide/preferences/index.html
[9] docs/api/java/util/ServiceLoader.html
[10] docs/api/java/lang/System.html
[11] tutorial/essential/environment/examples/PropertiesTest.java
[12] docs/api/java/lang/SecurityException.html
[13] docs/guide/security/index.html
[14] docs/api/java/lang/SecurityManager.html
[15] docs/api/java/security/AccessControlException.html
[16] docs/api/java/util/Calendar.html
3.22.71.28