Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

running solaris from Java apllication

Status
Not open for further replies.
Running Solaris commands from Java applications
As a Solaris system administrator, developer, or end user, you may have looked at Java by now and decided that it's an environment worth investigating. The combination of a relatively simple object-oriented language with a platform-independent philosophy and browser integration has taken the industry by storm. More than just a good programming language, Java is a programming environment around which new industries--Java Bean components, Smart Cards, and Network Computers to name a few--are being built. As I dug into Java from an administrator's perspective, my first questions centered around running Solaris commands from Java applications. If you're interested in how you might use Java programs for system administration, then this article is for you. In this article, we'll tackle the first important skill--running Solaris commands from within your custom Java applications.

A first example
Beginning with the JDK 1.0, Java has provided a way to run system commands from Java applications for all operating system environments. For Solaris administrators interested in writing Java programs that run Solaris commands, the Java classes named Process and Runtime give the Java program access to some of the pieces underlying the operating system. The Runtime class provides an exec() method that lets the Java programmer run commands. You simply call the exec() method of the Runtime class, supplying the command string you want to run. The exec() method creates a Process object that runs the specified command.
Listing A shows a minimal Java program, named RunCommand, that runs a Solaris command (ps -ef) from a Java application. This code is minimized so much, in fact, that it ignores the output of the ps command after it's run! We'll take care of that problem a little later, but first let's dig into the code in Listing A to see what's happening.

Listing A: RunCmd

import java.io.*;

public class RunCommand {

public static void main(String args[]) {

try {
Process psef = Runtime.getRuntime().exec("ps -ef");
System.out.println("ran the ps -ef command");
System.exit(0);
}
catch (IOException e) {
System.out.println("Error occurred trying to run ps -ef");
System.exit(-1);
}
}
}

Now, let's see what this program is doing. Our program's first statement is the import statement, which specifies classes you want to use in your program. The import statement we used tells Java that we want access to all the classes in the java.io package. (We could choose only a specific class, but it's often simpler to use the whole package.)
The classes that comprise the java.lang package are used heavily in Java programs, so you needn't import the java.lang package: It's implicitly imported for you. Please note also that you can still access classes that you don't explicitly import. However, when you use them, you must fully qualify their names. For example, the IOException class is part of the java.io package. If we didn't include the java.io package, we'd have to use java.io.IOException each time we wanted to use this class. So, the import statement merely gives us a shorthand notation for writing our code.

The next line of code declares our new class named RunCommand. You must put your code inside a class, because all Java code exists inside of classes. Of course, you needn't name your class RunCommand--you can name it anything you want. However, you must declare your Java program inside of a class.

If you're new to object-oriented programming, declaring a class in a small program like this doesn't seem to make much sense. But once a program becomes just a little larger, the class approach of the object-oriented model becomes much more intuitive and elegant.

Now, how does a Java program know where to start? Well, if you've had any exposure at all to the C or C++ programming languages, you know that program execution starts in the main() function. The same is true in Java. As you can see, the rest of our program is inside the curly brackets of the main() routine. When you write Java applications (as opposed to applets) you'll see this same declaration for the main() function again and again.

Within the main() routine, you encounter Java's try/catch syntax. This syntax is Java's way of trapping errors, or exceptions, that may occur while a program is running. I like to think of this syntax as meaning "go ahead and try this block of commands, but if an error happens, stop running those commands, and run the commands in the catch block instead." So, if an exception occurs, Java catches the error and continues to run, instead of failing completely. As you work with Java, you'll find this syntax a powerful way of handling all sorts of possible errors in your Java programs.

Applying this syntax to our program in Listing A, the Java interpreter will try to run the three commands inside the try block. Specifically, we'll try to create a new Process in which to run the ps -ef command. Next, the program prints a message to inform you that the ps -ef command ran, then it'll exit. However, if any of those commands fail because of an I/O exception, Java will start executing the code in the catch block: running the print statement and System.exit(-1) command instead. If no error occurs, then the program ignores the catch block entirely.

The method System.out.println() is similar to an echo statement in the C, Bourne, or Korn shells: It simply writes the text you specify to standard output. The System.exit(x) method is Java's way of returning an exit status of x to the caller. It's the same as the exit statement in the Bourne shell.


Compiling and running your Java program
After you've written your code, running a Java program is more like running a C/C++ program than running a shell script. Unlike a shell script, you can't just save this code to a file, change its permissions, then run it. With Java, you save the file, compile it, and run the compiled code through the Java interpreter. First, you should save the code in a file named RunCommand.java. Next, you must compile this source code file into a Java byte-code .class file. You do this by running the Java compiler, named javac:
$ javac RunCommand.java

This command creates a class file named RunCommand.class, which contains your platform-independent Java byte-code. Once you've created this file, you can run it on any platform that has a Java interpreter.
When you want to run this program, you run it through the Java interpreter, java. In our case, after compiling the code in Listing A, run the code through the Java interpreter as follows:

$ java RunCommand

This command loads the Java byte-code interpreter, telling it which class to start with. So java loads the RunCommand.class file and begins executing it at the function named main(). If everything ran successfully, the output from this program should be
ran the ps -ef command

Although this result isn't very useful, you've just run the ps -ef command from a Java program. Once you learn how to read the output from the ps -ef command and print that output to your terminal, you're ready to add a variety of Solaris commands to all of your Java applications.

Reading the output of the Solaris command
In order to start the ps -ef command in our program, we created a Process object. When you create a new Process object, Java allows you access to the standard input, output, and error streams of the new Process, so you can communicate with the running program. In our example, we've named our Process object psef. All Process objects have a built-in method named getInputStream() that connects the standard output of the running process into the specified input stream coming into your Java application. As an administrator, since you're comfortable with the Solaris concepts of standard input, standard output, and standard error, you should feel right at home with the idea of an input stream.
As a programmer using Java, it's easiest to convert a raw input stream like this into something far more useful, specifically a DataInputStream. A raw input stream, such as the stream provided by the Process object's getInputStream() method, isn't very convenient, whereas a DataInputStream is easy to work with.

Therefore, our first step toward reading the output of the ps -ef command is to convert the Process object's raw input stream into a DataInputStream object. This is easily accomplished with the following Java code:

DataInputStream dis = new DataInputStream(

To make our Java application run faster, we'll also buffer the input stream by using a BufferedInputStream class. In our tests, buffering the input stream improves the read performance almost ten-fold and is well worth any extra code. Instead of adding an extra line of code to the program, simply insert the BufferedInputStream method call between the raw psef object and the DataInputStream method call, like this:
DataInputStream dis = new DataInputStream(

Now, any time you want to read the input stream, simply read from the DataInputStream object dis, using the methods of the DataInputStream class. For instance, after invoking the commands above, it's easy to read from dis using the DataInputStream object's readLine() method. To read the first line of input from the ps -ef command, you'll use this code:
String s;
s = dis.readLine();

This command gets the first line of input from the DataInputStream object dis and puts that data into the String variable named s. In order to read every line of output of the ps -ef command, you should put the readLine() method into a while loop. In the while loop, you'll keep reading the output of the ps -ef command until the readLine() method returns a null value. You'll get a null value when there's no more output from the ps -ef command. In Java, you'll create the while loop like this:
String s;
while ((s = dis.readLine()) != null) {
// process the string "s" here ...

Putting it all together
Listing B shows a new version of our program, named RunPScommand, where we invoke the ps -ef command, attach a DataInputStream object to the output of the ps -ef command. Then we read each line from the DataInputStream object with the readLine() method and print the value of the string s to the standard output.
import java.io.*;

public class RunPScommand {

public static void main(String args[]) {

try {
Process psef = Runtime.getRuntime().exec("ps -ef");

DataInputStream dis = new DataInputStream(
new BufferedInputStream(
psef.getInputStream() ) );

while ((s = dis.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}

catch (IOException e) {
System.out.println("Error: Tried to run ps -ef");
System.exit(-1);
}
}
}

To run this program you'll need to perform the same steps you did previously. Simply save your changes to the RunPScommand.java file, compile the Java source code into a class module, then run it, like so:
$ javac RunPScommand.java
$ java RunPScommand
ran the ps -ef command
UID PID PPID C STIME TTY TIME CMD
root 0 0 0 Nov 01 ? 0:00 sched
root 1 0 0 Nov 01 ? 0:01 /etc/init -
root 2 0 0 Nov 01 ? 0:00 pageout
root 3 0 0 Nov 01 ? 2:12 fsflush

Some other thoughts
The methods demonstrated in this article let you run Solaris commands from Java applications on your Solaris workstations. You shouldn't confuse this action with running commands from Java applets in Internet browsers, which is a bit different. Because of the security model used for Java applets running in browsers, we must tackle a few more issues, which we'll do in a future article. Please note also that some fundamental changes in Java have occurred between the versions implemented in the JDK version 1.0 and version 1.1. For example, the readLine() method is now deprecated (i.e., works in version 1.1, but you shouldn't use it in new programs, because it won't be supported in the next version of Java.) In a nutshell, this means that although these classes will still be included in the JDK, you should begin using the newer classes as soon as possible. Because there's still a mixture of JDK 1.0 and 1.1 users out there, we supplied the code that works with both developer kits.

Conclusion
There's no question that using Java to run Solaris commands is more difficult than running the same commands inside of a shell program. But remember, this is just the start. By developing your own custom classes, you can make the entire process as easy as this:
DataInputStream dis = new SolarisCommand("ps -ef");

Also, if your goal is to run Solaris commands from a graphical interface, Java is rapidly becoming the simplest language to use to create cross-platform GUI applications. Finally, this same approach can lead you down the road of running Solaris commands from Internet browsers. .

F. regal
good luck
"think twice and hit enter once"
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top