Section 4.3. The System Class


4.3. The System Class

The Java System class provides some of the answers to questions about our environment. What follows is not an exhaustive discussion of all the methods in the System class, but only of those areas that touch on our specific focusinput/output (I/O) and environment variables.

Be aware that all of the methods in the System class are static. Therefore you never need to (and you can't) call a constructor on System. You just use the "class name, dot, method name" syntax to call the method (e.g., System.getProperties()). Similarly, the accessible fields in System are all static, so for some of the I/O-related methods you use the "class name, dot, field name, dot, method name" syntax (e.g., System.out.println()). As of Java 5.0, you can shorten this, by using a static import, that is:

 import static java.lang.System.*; 

Then in your other references you can leave off System, for example, getProperties() and out.println().

4.3.1. Java and Standard I/O

Java adopted the UNIX concept of standard I/O (see Section 1.3.1.1). The Linux file descriptors are available to a running Java program as I/O streams via the System class. The System class contains three public static fields named in, out, and err. You've probably already seen out in Java programs with statements like this:

 System.out.println("Hello, world."); 

You can also write:

 System.err.println("Error message here\n"); 

and

 BufferedReader in = new BufferedReader(new                         InputStreamReader(System.in)); while ((line = in.readLine()) != null) { ... } 

Java parallels Linux nicely on I/O descriptors. If you redirect any of those file descriptors from the shell command line when you execute a Java program, then that redirected I/O is available to your Java applicationwith no additional work on your part.

In the example above, if you have System.in all wrapped up into a BufferedReader from which your program is reading lines, then you can run that program as:

 $ java MyCode 

and it will read input as you type it on your keyboard. This may be how you test your program, but when you put this program to its intended use, you may want it to be able to read from a file. This you can do without any change to the programthanks to file descriptors, input streams, and redirecting input, for example:

 $ java MyCode < file2 

which will let the same Java program read from the file named file2 rather than from keyboard.

Your Java program can also set the values of System.in, System.out, and System.err as it executes, to change their destinations.

One common example is changing the destination of System.out, the typical recipient of debugging or logging messages. Say you've created a class or even a whole package of classes that write log messages to System.out (e.g., System.out.println("some message")). Now you realize that you'd like the output to go somewhere else.

You could redirect standard out, as in:

 $ java SomeClass > log 

but that requires the user to remember to redirect the output every time the program is invoked. That's fine for testing, or if the output is intended to go to a different place each time it is invoked. But, in this example, we always want the output to go to the same location.

Without changing any of the System.out.println() statements, all the messages can be sent to a new location by reassigning the System.out print stream. The System class has a setter for outthat is, a method which will let you set a new value for out. In your Java program, open the new destination file and give this to the System class:

 PrintStream ps = new PrintStream("pathname"); System.setOut(ps); 

It will be used from that point forward in the execution of this program as its out output stream.

Caution

Changing standard out (or in, or err) will make the change for all classes from here on in this invocation of the Java runtimethey are static fields of the one System class. Since this is so serious a move, the Java Security Manager (see Section 5.8.4.2) provides a check for setIO to see if the Java program is allowed to make such changes. If such a security manager is in place and you are not allowed to make such changes, an exception (SecurityException) will be thrown. Note also that the permission applies to setting any of the fields; it doesn't divide the permission into setting one (e.g., out) but not another (e.g., in).


4.3.2. Environment Variables

When Linux programs are run they have the open file descriptors described above. They also carry with them a list of "name=value" pairs called their environment. These environment variables allow for context to be shared among several successively executed programs. Some examples of environment variables are:

  • USER is the name you used to log in.

  • HOME is the directory where you start when you log in.

  • PATH is the list of directories searched for executable files.

To see the environment variables defined in your current shell, type env at the command prompt:

 $ env HOME=/home/user01 USER=user01 PATH=/bin:/usr/bin:/usr/local/bin:/home/user01/bin ... $ 

The names of environment variables, sometimes referred to as shell variables, are traditionally uppercase, though that is only a convention. The variable names are treated in a case sensitive fashion (e.g., Home != HOME).

You can set environment variables for use in the current shell with a simple assignment statement:

 $ VAR=value 

That will set the value for the duration of this shell, but not for any of its subprocesses. Since running another program is a subprocess, such an assignment won't be visible in your running program. Instead, you can export the variable so that it is carried forward to all subprocesses: [1]

[1] If you are using csh (the C-shell, another Linux command-line interpreter), then the syntax is slightly different. Instead of export name=value use setenv name value (note the different keyword and no equal sign).

 $ export VAR=value 

4.3.3. Java and Environment Variables

If these environment variables are available to all Linux processes, then how do we get at them from a Java program? Well, we can't do it quite as directly as you might think. In previous (1.2 and older) versions of Java, the System class had a getenv() method. Its argument was a String name of an environment variable and it returned the environment variable's value as a String. This has been deprecated. In fact, an attempt to use getenv() in more recent versions of Java will result in an exception. Sun decided that this was too platform-specific; not all platforms have environment variables.

Example 4.2. Java program to dump environment variables
 /*  * simple environment examiner  */ import java.util.*; public class AllEnv {   public static void   main(String [] args)   {     Properties props = java.lang.System.getProperties();     for (Enumeration enm = props.propertyNames(); enm.hasMoreElements();)     {       String key = (String) enm.nextElement();       System.out.print(key);       System.out.print(" = ");       System.out.println(props.getProperty(key));     }    } // main }  // class AllEnv 

Now (Java 1.3 and beyond) the preferred approach is to use the getProperties() and getProperty() methods of the System class. How are these different from the getenv() approach? To a Linux developer, getenv() was easy and straightforwardjust not very portable. To accommodate other systems, Java defines a set of properties that are reasonable to expect to be defined on any system, and provides a Java property name for each one.

To see the entire list, call the getProperties() method. It returns a Properties class, which is an extension of the Hashtable class. From this class you can get an Enumeration of the names, as Example 4.2 demonstrates.

Now compile and run this example:

 $ javac AllEnv.java $ java AllEnv 

and you will get a long list of propertiesin no particular order. They are kept in a hashtable and thus not sorted. Of course it would be easier to use this list if they were sorted. Linux to the rescue.

 $ java AllEnv | sort 

It's often in simple little steps like this that one begins to see the power of Linux. In Linux, not every desirable feature has to be crammed into every possible place where it might be used. Instead, features can be written once and connected to one another as needed. Here what we need is to have the list of properties sorted. We don't need to worry that our class didn't sort its output. In Linux we just connect the standard output of the Java program with a sort utility that Linux provides.

So what are all these properties? Many of them have to do with Java-related information (java.version, and so on), but a few are more general. Those that parallel the typical Linux environment variables are:

  • file.separator is the file separator ("/" on Linux).

  • path.separator is the path separator (":" on Linux).

  • line.separator is the line separator ("\n" on Linux).

  • user.name is the user's account name.

  • user.home is the user's home directory.

  • user.dir is the user's current working directory.

But that leaves out so many environment variables, especially the application-specific ones (e.g., CVSROOT). How would a Java program get at these?

Because of this new, more portable way to describe the environment, there is no easy way to get at other environment variables. There are a few approaches, but they are all indirect.

First, you can add to the properties list by defining new properties on the command line when invoking the program, for example:

 $ java -Dkey=value AllEnv 

You can list several properties on the line by repeating the -D parameter:

 $ java -DHOME=/home/mydir -DALT=other -DETC="so forth" AllEnv 

Instead of typing those values, you'd probably want to let the Linux shell put in the values from its environment. So you'd use shell variables, for example:

 $ java -DHOME="${HOME}" -DALT="${ALT}" -DETC="${ETC}" AllEnv 

assuming that HOME, ALT, and ETC have already been defined in the shell's environment. [2]

[2] The quotations around the shell variables keep any embedded spaces as part of the variable's value. The curly braces are not strictly necessary in this use.

If there are only a few variables that you need to pass to Java, put them on the command line as shown above. Put that command line into a shell script and use the script to invoke the program so that the parameters are supplied every time.

But if you want to access many or all of the environment variables then you may want to do something a little more complex. Notice the syntax of the output of the env command. It is in the same format (name=value) as are properties. So if we use a shell script to invoke our program, we can have it place all these values into a file by redirecting output, then open this file as a Java properties file and thus make all the name/value pairs accessible.

The following commands in a shell script attempt to do just that:

 env > /tmp/$$.env java -DENVFILE=/tmp/$$.env MyClass rm /tmp/$$.env 

where MyClass is the Java program that you wish to run.

Tip

The shell variable $$ is the numeric process ID of the running process. This provides a unique ID during each invocation of the program. Each run of the script will have its own process and thus its own process ID. Thus a single user could execute this script multiple times concurrently without fear of collision with himself or others.


We remove the temporary file with the rm command in the last line of the script to avoid cluttering our /tmp directory with lots of these files.

But now we have to add code to MyClass to open the file defined by ENVFILE and read the properties it contains. This leads us naturally to the Java Properties class, the subject of our next section, where we'll talk more about this example.



    Java Application Development with Linux
    Java Application Development on Linux
    ISBN: 013143697X
    EAN: 2147483647
    Year: 2004
    Pages: 292

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