Package Torello.Java
Class OSCommands
- java.lang.Object
-
- Torello.Java.OSCommands
-
- All Implemented Interfaces:
java.lang.Cloneable
public abstract class OSCommands extends java.lang.Object implements java.lang.Cloneable
Root Ancestor / Parent Class for all Operating-System Execution Classes - including:MSDOS
,Shell
,GSUTIL
etc... This class serves as the root or parent class of all classes in this package which have been designed to start Operating System Calls. This class is generally a wrapper around several basic but important classes from thejava.lang
Package. These are listed below, and the functionality and features they provided are greatly expanded by this classOSCommands
, and all the descendant clases that extend it.class java.lang.Runtime
class java.lang.Process
class java.lang.ProcessBuilder
class java.lang.ProcessBuilder.Redirect
Do note that one of the motivating forces for writing these classes is merely to serve as explanation and example of using Java's classjava.lang.Process
. Quite a bit of work was done writing the reader and monitor threads to ensure that the output of executing a UNIX command is collected and returned properly. This class generates a simple instance ofOSResponse
whenever a command is invoked. This returned class contains several fields that have all the information produced by executing an O/S command.
Wildcard Issue:
On most UNIX platforms, whenever a command is issued to the O/S (by typing it, for example, inside a terminal or terminal-window) there is an execution-stage before the process is spawned where file-name and / or directory-name wildcards (usually:'*'
and'?'
) are expanded.
When a UNIX command receives a parameter list, if the file and/or directories specified by the user contains wild-cards, those wild-cards shall have already been eliminated and replaced by the O/S when the that command receives its actual parameter list. The arguments that the terminal-command actually "sees" are the actual files and/or directories from which the wild-card expression expanded. A wild-card expression (like a "reg-ex expression") is replaced by the complete list of files before the command ever begins (usually!)
Because of this situation, if a user would like, for instance, tocopy
ormove
a group of files - and use Java to do it, then a native Java A.P.I. such as thepackage java.nio.*
(or the class class FileNode API) is really the only way to ensure that wild-card expressions actually work. It is usually easiest to request an array (or ajava.util.Stream
) of files using theFileNode.flatten(...)
routines, and then pass that list to the UNIX command.
WORA:
In its inception, Java made the "Write Once, Run Anywhere" (WORA) pledge. The methods in this class are not in any way "Java-ized" versions of the Operating System Calls. Rather, they are just wrappers aroundjava.lang.Process
allowing a user to BOTH make Operating System calls easily AND to efficiently retrieve the generated text-output produced by the calls.
The bulk-work of the classes in this JAR Library were written and tested in a UNIX environment. While everything else in theJava HTML JAR Library
is, indeed, O/S Independent (adhering to 'WORA'), this class and all classes which extendOSCommands
are not! In fact, they are highly O/S dependent. The methods in these classes are actually just a set of hooks into native Operating System calls.
This does mean that any invocation of these methods, when running in some other Operating System Environment, will just throw exceptions.
Hi-Lited Source-Code:This File's Source Code:
- View Here: Torello/Java/OSCommands.java
- Open New Browser-Tab: Torello/Java/OSCommands.java
File Size: 16,983 Bytes Line Count: 372 '\n' Characters Found
Thread Helper Class:
- View Here: ../Command Line/OSCHelper/Completed.java
- Open New Browser-Tab: ../Command Line/OSCHelper/Completed.java
File Size: 24,735 Bytes Line Count: 501 '\n' Characters Found
Thread Helper Class:
- View Here: ../Command Line/OSCHelper/ISPT.java
- Open New Browser-Tab: ../Command Line/OSCHelper/ISPT.java
File Size: 7,772 Bytes Line Count: 172 '\n' Characters Found
-
-
Field Summary
Collect & Log Process Output-Stream Character Data Modifier and Type Field Appendable
commandStrAppendable
Appendable
errorOutput
Appendable
outputAppendable
Appendable
standardOutput
Configure advanced / optional java.lang.ProcessBuilder settings Modifier and Type Field OSExtras
osExtras
-
Constructor Summary
Constructors Modifier Constructor OSCommands()
OSCommands(Appendable outputAppendable)
OSCommands(Appendable standardOutput, Appendable errorOutput)
OSCommands(Appendable outputAppendable, Appendable commandStrAppendable, Appendable standardOutput, Appendable errorOutput)
protected
OSCommands(OSCommands other)
-
Method Summary
Run-Method: used by Shell
,GSUTIL
andMSDOS
Modifier and Type Method OSResponse
printAndRun(String[] command)
Methods: interface java.lang.Cloneable Modifier and Type Method abstract OSCommands
clone()
Methods: class java.lang.Object Modifier and Type Method String
toString()
-
-
-
Field Detail
-
outputAppendable
public java.lang.Appendable outputAppendable
This is an instance ofjava.lang.Appendable
that will accept log text generated from this class'printAndRun
method. Since this class has the ability to send text to a terminal (likeSystem.out
, for instance); this field has been created to make it easy for the output from Operating System commands to printed to the screen, or just about anywhere (using thisAppendable
).
This global 'log' is automatically used for printing by the methods in this class, and it may be configured using anyObject
that implements thejava.lang.Appendable
interface.
public, non-final:
This field may be changed / modified at any time prior to the execution of a command. This field was intentionally declaredpublic
to allow a user to configure this class output-collection procedures as needed.
When an External / Operating-System command is executed, this field's reference-value is copied from this class to an internal, Thread-Safe, data-mirror class.
This expects an implementation of Java'sjava.lang.Appendable
interface which allows for a wide range of options when logging intermediate messages.Class or Interface Instance Use & Purpose 'System.out'
Sends text to the standard-out terminal Torello.Java.StorageWriter
Sends text to System.out
, and saves it, internally.FileWriter, PrintWriter, StringWriter
General purpose java text-output classes FileOutputStream, PrintStream
More general-purpose java text-output classes
Checked IOException:
TheAppendable
interface requires that the Checked-ExceptionIOException
be caught when using itsappend(...)
methods.
-
commandStrAppendable
public java.lang.Appendable commandStrAppendable
If a user wishes to print just the command being issues as text to some Java appendable, then a reference should be assigned to thispublic static
field. This will guarantee that any time any command from this class is issued, the text of that command will be printed to this outputjava.lang.Appendable
As should be noted, by defualt, this feild has been set to null. When this field is null, it will be ignored completely.
Use of this Field:
Occasionally, as projects grow in size, the logging features of a project become ever more important. In such cases, one choice / "avenue" for output printing & logging can be to allow printing all output to a single outputAppendable
and simultaneously printing just the command text to a secondjava.lang.Appendable
.
Thisjava.lang.Appendable
field is solely used for printing the command text itself. It operates comletely independent from the other fields: appendable and cmdOrCmdAndOutput.
public, non-final:
This field may be changed / modified at any time prior to the execution of a command. This field was intentionally declaredpublic
to allow a user to configure this class output-collection procedures as needed.
When an External / Operating-System command is executed, this field's reference-value is copied from this class to an internal, Thread-Safe, data-mirror class.
-
standardOutput
public java.lang.Appendable standardOutput
When this field is non-null, it shall receive all text that the underlying process sends toStandard Output
. When this field is null, it is ignored.
The default constructor for this class assigns 'null' to this field. Bear in mind that even when thisAppendable
is null, the underlying process being executed will continue to have itsStandard Output
text saved to an internal,private
, buffer. This buffer's contents will stil be available inside the returned instance field:OSResponse.standardOutput
The motivating force for the decision to provide anotherAppendable
for loggingStandard Output
was so that a user may receive this pipe's text output in real time, as the process executes, without having to wait for the process to run to completion.
There are numerous networked file-system operations (for instance) that may require several minutes to finish, and setting thisAppendable
allows a user to receive error notices as they happen, rather than waiting for the operation to complete.
public, non-final:
This field may be changed / modified at any time prior to the execution of a command. This field was intentionally declaredpublic
to allow a user to configure this class output-collection procedures as needed.
When an External / Operating-System command is executed, this field's reference-value is copied from this class to an internal, Thread-Safe, data-mirror class.
-
errorOutput
public java.lang.Appendable errorOutput
When this field is non-null, it shall receive all text that the underlying process sends toError Output
. When this field is null, it is ignored.
The default constructor for this class assigns 'null' to this field. Bear in mind that even when thisAppendable
is null, the underlying process being executed will continue to have itsError Output
text saved to an internal,private
, buffer. This buffer's contents will stil be available inside the returned instance field:OSResponse.errorOutput
The motivating force for the decision to provide anotherAppendable
for loggingError Output
was so that a user may receive this pipe's text output in real time, as the process executes, without having to wait for the process to run to completion.
There are numerous networked file-system operations (for instance) that may require several minutes to finish, and setting thisAppendable
allows a user to receive error notices as they happen, rather than waiting for the operation to complete.
public, non-final:
This field may be changed / modified at any time prior to the execution of a command. This field was intentionally declaredpublic
to allow a user to configure this class output-collection procedures as needed.
When an External / Operating-System command is executed, this field's reference-value is copied from this class to an internal, Thread-Safe, data-mirror class.
-
osExtras
-
-
Constructor Detail
-
OSCommands
public OSCommands()
This constructor assigns default values to all of the output loggingAppendable's
.
Note that all of them are assigned 'null' - meaing their output will not be logged - except for the primary outputAppendable
field.this.outputAppendable
. This field is assignedSystem.out
, meaning that all text output by a process will be sent to the terminal window.
-
OSCommands
public OSCommands(java.lang.Appendable outputAppendable)
This constructor allows a user to assign an instanceAppendable
to:appendable
.
The first collects all text-output generated by the processes and prints it using theAppendable's
printing methods. This includes text generated for BOTHStandard-Output
ANDError-Output
. This text is collected in real time as it is output by the underlying process.
Assigning null:
Any of this classAppendable's
may be assigned null. When anAppendable
is assigned null, it is simply ignored.NullPointerException
will not throw, and any output text that would be appended, isn't appended.- Parameters:
outputAppendable
- This parameter's reference is assigned directly to theOSCommands
field:appendable
. To clearly understand the use of this field, please review the documentation linked for that field. To summarize, thejava.lang.Appendable
that is synonymously namedappendable
simply collects all output text generated by a processes as it executes, and sends it to the reference'sappend(...)
method. This text will include that sent to BOTHStandard-Output
AND text sent toError-Output
. The text that is printed is transmitted in the order it is received from the reader-threads that read the underlying process' text-pipes.
By default this parameter is assignedSystem.out
. When this default value is used, it means that as the process executes, any and all text it prints is sent to the UNIX or MS-DOS Operating System Terminal Window.
This field may be assigned null, and when so it is just ignored. Assigning null toappendable
. will not produce aNullPointerException
.- See Also:
outputAppendable
- Code:
- Exact Constructor Body:
this.outputAppendable = outputAppendable;
-
OSCommands
public OSCommands(java.lang.Appendable outputAppendable, java.lang.Appendable commandStrAppendable, java.lang.Appendable standardOutput, java.lang.Appendable errorOutput)
Constructor that allows for assigning all four text-collectingAppendable's
. Please review the documentation for each of these fields to understand better how theseAppendable's
may be used. There are links in the See-Also section, below.
Assigning null:
Any of this classAppendable's
may be assigned null. When anAppendable
is assigned null, it is simply ignored.NullPointerException
will not throw, and any output text that would be appended, isn't appended.- Parameters:
outputAppendable
- This parameter's reference is assigned directly to theOSCommands
field:appendable
. To clearly understand the use of this field, please review the documentation linked for that field. To summarize, thejava.lang.Appendable
that is synonymously namedappendable
simply collects all output text generated by a processes as it executes, and sends it to the reference'sappend(...)
method. This text will include that sent to BOTHStandard-Output
AND text sent toError-Output
. The text that is printed is transmitted in the order it is received from the reader-threads that read the underlying process' text-pipes.
By default this parameter is assignedSystem.out
. When this default value is used, it means that as the process executes, any and all text it prints is sent to the UNIX or MS-DOS Operating System Terminal Window.
This field may be assigned null, and when so it is just ignored. Assigning null toappendable
. will not produce aNullPointerException
.commandStrAppendable
- Thisjava.lang.Appendable
allows for yet another output mechanism when executing operating system commands. The sole purpose of thisAppendable
is to print the process command, itself, as a JavaString
- exactly as it was issued to the operating system.
This allows a type of "Monitor Log" to store all commands being issued to the Operating-System, without having to include the full-text output that those process calls have produced. The value passed to this parameter is assigned to theOSCommands
field namedprintCmdAppendable
.
This parameter may be null, and if it is, no such output will be generated.standardOutput
- ThisAppendable
is assigned to the internalOSCommands
field:standardOutput
. ThisAppendabe
, as the name hopefully implies, allows a user to collect any / all text sent by the process toStandard-Output
.
Please review the documentation for that field to better understand it's use. Also, keep in mind that null may be passed to this parameter, and if / when it is the correspondingAppendable
field will simply be ignored during the process execution.errorOutput
- ThisAppendable
is assigned to the internalOSCommands
field:errorOutput
. ThisAppendabe
, as the name hopefully implies, allows a user to collect any / all text sent by the process toError-Output
.
Please review the documentation for that field to better understand it's use. Also, keep in mind that null may be passed to this parameter, and if / when it is the correspondingAppendable
field will simply be ignored during the process execution.- See Also:
outputAppendable
,commandStrAppendable
,standardOutput
,errorOutput
- Code:
- Exact Constructor Body:
this.outputAppendable = outputAppendable; this.commandStrAppendable = commandStrAppendable; this.standardOutput = standardOutput; this.errorOutput = errorOutput;
-
OSCommands
public OSCommands(java.lang.Appendable standardOutput, java.lang.Appendable errorOutput)
This constructor assigns values to these internalAppendable
fields:standardOutput
anderrorOutput
Assigning null:
Any of this classAppendable's
may be assigned null. When anAppendable
is assigned null, it is simply ignored.NullPointerException
will not throw, and any output text that would be appended, isn't appended.- Parameters:
standardOutput
- ThisAppendable
is assigned to the internalOSCommands
field:standardOutput
. ThisAppendabe
, as the name hopefully implies, allows a user to collect any / all text sent by the process toStandard-Output
.
Please review the documentation for that field to better understand it's use. Also, keep in mind that null may be passed to this parameter, and if / when it is the correspondingAppendable
field will simply be ignored during the process execution.errorOutput
- ThisAppendable
is assigned to the internalOSCommands
field:errorOutput
. ThisAppendabe
, as the name hopefully implies, allows a user to collect any / all text sent by the process toError-Output
.
Please review the documentation for that field to better understand it's use. Also, keep in mind that null may be passed to this parameter, and if / when it is the correspondingAppendable
field will simply be ignored during the process execution.- Code:
- Exact Constructor Body:
this.outputAppendable = null; this.standardOutput = standardOutput; this.errorOutput = errorOutput;
-
OSCommands
protected OSCommands(OSCommands other)
Clone-Constructor. This is used by sub-classes to allow for aclone()
method.- Parameters:
other
- This is an instance that is passed by a'clone'
method. It is always just'this'
.- Code:
- Exact Constructor Body:
this.outputAppendable = other.outputAppendable; this.commandStrAppendable = other.commandStrAppendable; this.standardOutput = other.standardOutput; this.errorOutput = other.errorOutput; this.osExtras = other.osExtras;
-
-
Method Detail
-
printAndRun
public OSResponse printAndRun(java.lang.String[] command) throws java.io.IOException
Executes a command by spawning an operating-system process.
Sub-Class Note:
If you are intending to write an extension of this class for executing Operating System Commands, this method here should be used as the launch-pad for invoking those commands.
Please review the classesShell
orMSDOS
to see how to employ a Shell-Script Class to extend this class ('OSCommands'
), and specifically how to invoke this method to run those scripts.- Parameters:
command
- AString[]
-Array Shell / UNIX / MSDOS Command. This parameter (and this method) are usually created/invoked by the classesShell
,GSUTIL
,MSDOS
etc...- Returns:
- Returns an instance of
OSResponse
. This response-Object
(data-record) class holds fourpublic, final
fields:
① Processresponse-code
② Text sent toStandard-Output
(as ajava.lang.String
)
③ Text sent toError-Output
(also as aString
)
④ The original Command-String
ThisOSResponse
instance may be discarded without any effect onProcess
Execution. It is only provided as a convenience in case more information is required about the results of theO/S
command invocation.
Process Status: Upon completion of this method, theOperating-System java.lang.Process
is guaranteed to have run to completion (or to have failed and been interrupted). If the process was interrupted, theresponse-code
will indicate this using the valueINTERRUPTED
- Throws:
java.io.IOException
- Code:
- Exact Method Body:
final ThreadSafeSnapshot config = new ThreadSafeSnapshot(); final boolean hasOSE = (config.osExtras != null); this.osExtras = null; // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Do as much error / exception checking as is possible... (It isn't much) // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** for (int i=0; i < command.length; i++) if (command[i] == null) throw new NullPointerException( "The " + i + StringParse.ordinalIndicator(i) + " array element in the 'command' " + "(O/S Command) array-parameter that was passed to this method was 'null'. " + "Java's method Runtime.getRuntime().exec(command) will not accept a 'command' " + "array that contains any nulls." ); if (hasOSE && config.osExtras.currentWorkingDirectory != null) if (! config.osExtras.currentWorkingDirectory.isDirectory()) throw new IllegalArgumentException( "The file-system has stated that the reference passed to parameter " + "'currentWorkingDirectory' was not a valid directory on the file-system: " + '[' + config.osExtras.currentWorkingDirectory.getPath() + ']' ); // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Run the "Command String Appendable" output-logger thingy // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** final StringBuilder sb = new StringBuilder(); for (int i=0; i < command.length; i++) sb.append(command[i] + " "); sb.append('\n'); // This is needed again at the end of this method final String commandStr = sb.toString(); if (config.commandStrAppendable != null) config.commandStrAppendable.append(commandStr); // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Now execute the command! // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Used to build the String's for this class standardOutput and errorOutput fields! final StringBuilder standardOutputSB = new StringBuilder(); final StringBuilder errorOutputSB = new StringBuilder(); try { // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // First, build a java.lang.Process object-instance // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // This is the java.lang.Process class instance. It is built with a simple constructor // unless the user has passed all of the OSExtras stuff. If 'hasOSE' is true, then a // java.lang.ProcessBuilder object is needed to actually build the Process // // The end of this (kind of long) if-then-else statement has a simply assignment // ==> pro = Runtime.getRuntime().exec(command); Process pro; if (hasOSE) { // Save some typing, that's all! final OSExtras x = config.osExtras; // This will create a process with specified modifications ProcessBuilder b = new ProcessBuilder(command); // NOTE: These "extra" configurations aren't so useful. HOWEVER, this is the only // reason this method is provided. Normally, you would use the other method // with the exact same name (Which leaves out all of these re-directs). If you // have opted to use this method, instead of the one that leaves these things // out, the redirects are set here! All they do is ask the OS Process to do that // "Operating System Thing" were input and/or output are retrieved/sent to a file if (x.currentWorkingDirectory != null) b.directory(x.currentWorkingDirectory); if (x.mergeStdErrorAndStdOut) b.redirectErrorStream(true); if (x.outputRedirect != null) b.redirectOutput(x.outputRedirect); if (x.inputRedirect != null) b.redirectInput(x.inputRedirect); if (x.errorRedirect != null) b.redirectError(x.errorRedirect); if (x.environmentVariableUpdater != null) x.environmentVariableUpdater.accept(b.environment()); pro = b.start(); } // Otherwise just call this version - if there are no "OSExtras" else pro = Runtime.getRuntime().exec(command); // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Now just collect output with the (Java-HTML internal) "ISPT" Printer-Reader Threads // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // These 3 lines create a "Completion Monitor" instance, and then register the // "Reader Threads" for reading from Standard-Out and Standard-Error from the Process. // These create two "Daemon Threads" that read process-output and error-output using // Java Thread's. These will not hang **UNLESS** one of the InputStream read method's // hang/lock. Completed completed = new Completed(); // Note that the constructor's below start the printer/reader/monitors - there is no // need to actually keep a reference/pointer to these classes once they are // constructed. Passing 'completed' to these constructors is enough! // // ALSO: It is completely immaterial whether/if any of the three appendable's passed to // the TriAppendable-Constructor are actually null. Note that only the one whose // name ends with "SB" is guaranteed not to be null. The other two // (user-provided) Appendable's can easily be null! new ISPT( pro.getInputStream(), new TriAppendable( config.outputAppendable, standardOutputSB, // OSResponse uses this for it's standardOutput field config.standardOuput ), completed, "Thread for Reading from Standard Output" ); new ISPT( pro.getErrorStream(), new TriAppendable( config.outputAppendable, errorOutputSB, // OSResonse uses this for it's errorOutput field config.errorOutput ), completed, "Thread for Reading from Error Output" ); // NOTE: The process, once it is instantiated, is already running. There is no // need to "start" the process, the call to Runtime.exec (above does that). Here // we can just wait for the reader threads to receive the EOF messages, which is // how they terminate. completed.waitForCompletionOfAllThreads(); // It is unlikely this would cause the current thread to wait, because the previous // line will wait until both Standard-Out and Error-Out have received EOF... // Perhaps the process COULD delay the return response-code here. The reality is that // method 'waitFor' is the PREFERRED way to retrieve the exit-value from this process... // although method 'Process.exitValue()' would also probably work. int response = pro.waitFor(); // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // Return the 'OSResponse' result (or throw an exception, if the process threw one) // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** // This prints a friendly little message at the end stating what the response-code was if (config.outputAppendable != null) config.outputAppendable.append ("Command exit with return value " + response + '\n'); completed.ifExceptionThrowException(); // Note that a '0' response-code usually means 'succesfully terminated' return new OSResponse (commandStr, response, standardOutputSB.toString(), errorOutputSB.toString()); } catch (InterruptedException e) { return new OSResponse( commandStr, OSResponse.INTERRUPTED, standardOutputSB.toString(), errorOutputSB.toString() ); }
-
toString
public java.lang.String toString()
Generates aString
this class. The returnedString
merely encodes the class-names of the non-nullAppendable's
.- Overrides:
toString
in classjava.lang.Object
- Returns:
- A simple representation of this class, as a
java.lang.String
- Code:
- Exact Method Body:
// private static String toStrApp(Appendable a) // { return (a == null) ? "null\n" : (a.getClass().getName() + '\n'); } return "outputAppendable: " + toStrApp(this.outputAppendable) + "commandStrAppendable: " + toStrApp(this.commandStrAppendable) + "standardOutput: " + toStrApp(this.standardOutput) + "errorOutput: " + toStrApp(this.errorOutput);
-
clone
public abstract OSCommands clone()
Creates a clone of'this'
instance. Though unlikely of much use, this could conceivably have some function if similar, but non-identical, output mechanisms were being used.- Overrides:
clone
in classjava.lang.Object
- Returns:
- An exact copy of
'this'
instance - one in which all outputAppendable's
have had their references copied into the new instance.
-
-