Class ExternalProcessor

java.lang.Object
net.algart.arrays.ExternalProcessor
All Implemented Interfaces:
Closeable, AutoCloseable, ArrayProcessor

public class ExternalProcessor extends Object implements ArrayProcessor, Closeable

A tool helping to call external programs (OS processes) for processing AlgART arrays and matrices.

This class helps to solve two following main tasks.

  1. Creation of some disk directory (work directory) for exchanging data with the called external program. This class provides automatic creation of the work directory (in getInstance(ArrayContext, String, String) / getInstance(ArrayContext) methods), automatic deletion of it after finishing usage of an external program (in close() method and in the finalizer) and the special cleanup(String) method for removing all work directories, which were not successfully deleted (usually due to file mapping or abnormal JVM termination) while previous usages of this class or while previous calls of your application.
     
  2. Support of the standard AlgART logic of interrupting the algorithm via ArrayContext.checkInterruption() method while execution of an external program: the basic execute(ProcessBuilder) method periodically calls checkInterruption(), and if it throws an exception (i.e. the user wants to stop calculations), automatically terminates the external process via java.lang.Process.destroy() call.

This class also contains a collection of static method, useful while implementing inter-application communications.

The instances of this class are thread-safe: all non-static methods are internally synchronized (besides context() and getWorkDirectory(), that always return the same values and don't require synchronization, and the service methods getWorkFile(String), writeWorkUTF8(String, String), readWorkUTF8(String)). So, you may use the same instance of this class in several threads; but usually there is not sense to do it.

Unlike this, the static methods of this class (like cleanup(String)) are not thread-safe, but are thread-compatible and can be synchronized manually.

Author:
Daniel Alievsky
  • Field Details

    • TEMP_SUBDIRECTORY_DEFAULT_NAME

      public static final String TEMP_SUBDIRECTORY_DEFAULT_NAME
      The name of default temporary directory for creating work directories by instances of this class. Such subdirectory is created by getInstance(ArrayContext) method in the standard system temporary directory System.getProperty("java.io.tmpdir").

      The value of this constant is "algart__ep".

      See Also:
    • WORK_DIRECTORY_PREFIX

      public static final String WORK_DIRECTORY_PREFIX
      The prefix of unique work directories, created while instantiation of this class. See getInstance(ArrayContext, String, String) method about "work directory" concept.

      The value of this constant is "algart__ep_".

      Note: if you are planning to use cleanup(String) method, you must be sure that your temporary directory, passed to that method, never contains files or directories with names, started with this prefix, besides work directories created by this class. The reason is that cleanup(String) method automatically tries to recursively remove all such subdirectories. The simplest way to provide this condition is usage of the default temporary directory getDefaultTempDirectory(), for example, via cleanup() method without arguments: this directory is created by this class itself in the system directory System.getProperty("java.io.tmpdir") and, so, never contain extra files/subdirectories.

      See Also:
    • USAGE_MARKER_FILE_NAME

      public static final String USAGE_MARKER_FILE_NAME
      The name of a temporary file-marker, created inside work directories while instantiation of this class for internal use (see cleanup(String) method for more details). See getInstance(ArrayContext, String, String) method about "work directory" concept.

      The value of this constant is ".algart__ep_used".

      Note: you must guarantee that you will not try to create or write into a file with this name in the work directory.

      See Also:
    • JRE_PATH_PROPERTY_NAME

      public static final String JRE_PATH_PROPERTY_NAME
      The name of system property ("net.algart.arrays.jre.path"), used for finding some custom JRE by getCustomJREHome() method.
      See Also:
    • JRE_PATH_ENV_NAME

      public static final String JRE_PATH_ENV_NAME
      The name of environment variable ("NET_ALGART_ARRAYS_JRE_PATH"), used for finding some custom JRE by getCustomJREHome() method.
      See Also:
    • JVM_OPTIONS_PROPERTY_NAME

      public static final String JVM_OPTIONS_PROPERTY_NAME
      The name of system property ("net.algart.arrays.jvm.options"), used to get a list of custom JVM options by getCustomJVMOptions() method.
      See Also:
    • JVM_OPTIONS_ENV_NAME

      public static final String JVM_OPTIONS_ENV_NAME
      The name of environment variable ("NET_ALGART_ARRAYS_JVM_OPTIONS"), used to get a list of custom JVM options by getCustomJVMOptions() method.
      See Also:
  • Method Details

    • getInstance

      public static ExternalProcessor getInstance(ArrayContext context, String tempDirectory, String additionalPrefix)
      Creates new instance of this class.

      The newly created instance allows to execute, one or several times, some external OS command, usually another command-line application, via the call of execute(ProcessBuilder) method. Before finishing usage of this instance, you must call close() method; after this, you cannot use this object.

      This method automatically creates an unique temporary disk subdirectory, called the work directory, inside tempDirectory, which is supposed to be some global disk directory for storing temporary data. Usually you may pass the result of getDefaultTempDirectory() method here (or use the alternative method getInstance(ArrayContext)).

      The created work directory can be used for exchanging data with the external application, called by execute(ProcessBuilder) method. The method close() tries to completely remove this directory with all its files and subdirectories (you may cancel this action). You should understand, that it is possible that close() method will not be able to remove it, because some temporary files can be locked by OS — for example, if you map them via LargeMemoryModel. You can use cleanup(String) method at any time to remove all "garbage", i.e. work directories, created by this class (maybe while previous calls of your application), but not successfully deleted by close() methods.

      The created unique work directory always has a name, started with the character sequence
          WORK_DIRECTORY_PREFIX + additionalPrefix.
      Here WORK_DIRECTORY_PREFIX allows to detect subdirectories, created by this class, and additionalPrefix allows you (if you want) to distinguish subdirectories, created by different instance of this class for different goals. You must take this into consideration, when you specify some custom tempDirectory (different from getDefaultTempDirectory()). In this case, you should either be sure that WORK_DIRECTORY_PREFIX prefix cannot appear in other file/subdirectory names in this directory, or never use cleanup(String) method — because it will try to remove all subdirectories with names, started with WORK_DIRECTORY_PREFIX.

      Important note: this method tries to create the parent directory tempDirectory if and only if it is identical (in terms of String.equals()) to the result of getDefaultTempDirectory() method. In other case, the passed tempDirectory must already exist: new File(tempDirectory).exists() must return true.

      Note: you can use these features, even if you are not going to call external commands via execute(ProcessBuilder) method.

      Parameters:
      context - the context of execution; may be null, then will be ignored. In the current implementations, it is used only to allow the user to stop the running external application: see context() method.
      tempDirectory - the path to the global disk directory for allocating temporary data; in most cases you may pass here the result of getDefaultTempDirectory().
      additionalPrefix - some string, added to WORK_DIRECTORY_PREFIX to provide unique prefix for the the name of the work directory, created by this class; you may pass "", if you are not interested in it.
      Returns:
      new instance of this class.
      Throws:
      NullPointerException - if tempDirectory or additionalPrefix argument is null.
      SecurityException - if System.getProperty("java.io.tmpdir") call throws this exception.
      IOError - if this method cannot create an unique subdirectory due to some reasons, in particular, if !tempDirectory.equals(getDefaultTempDirectory()) and the corresponding path does not exist.
      See Also:
    • getInstance

      public static ExternalProcessor getInstance(ArrayContext context)
      Equivalent to getInstance(context, getDefaultTempDirectory(), "").
      Parameters:
      context - the context of execution; may be null, then will be ignored. In the current implementations, it is used only to allow the user to stop the running external application: see context() method.
      Returns:
      new instance of this class.
      Throws:
      SecurityException - if System.getProperty("java.io.tmpdir") call throws this exception.
      IOError - if this method cannot create an unique subdirectory due to some reasons, in particular, if !tempDirectory.equals(getDefaultTempDirectory()) and the corresponding path does not exist.
      See Also:
    • cleanup

      public static boolean cleanup(String tempDirectory)
      Tries to remove all work directories (recursively, with all their content), which were created by some instances of this class, instantiated by getInstance(ArrayContext, String, String) method with the same tempDirectory argument, and which were not successfully deleted yet.

      Such situation is possible, for example, when some temporary files, used for exchanging data with an external program, are locked by OS, and we cannot unlock them immediately after termination of the external program. It can be connected with file mapping (in particular, mapping via LargeMemoryModel, which is unmapped in Java while garbage collection only). Another typical reasons of appearing non-deleted work directories is canceling automatic deletion of work data for some instance of this class by cancelRemovingWorkDirectory() method or abnormal termination of your application, when close()were not called for some instance of this class.

      The cleanup technique, implemented in this method, is based on java.nio.channels.FileLock class. When an instance of this class is created, it places into its work directory an empty file with some reserved name USAGE_MARKER_FILE_NAME and locks it via FileLock. When an instance finishes working, i.e. when its close() method is called, it unlocks this file and removes it. It is obvious that all locked files are unlocked when the application is terminated, normally or abnormally. So, if tempDirectory contains some subdirectory, the name of which is started with WORK_DIRECTORY_PREFIX and which does not contain a file with the name USAGE_MARKER_FILE_NAME or contains such a file, but it is not locked, it means that this subdirectory is a "garbage" and can be removed. This method tries to remove all such subdirectories and returns true, if it has successfully removed all content of tempDirectory.

      Note: if this method was not able to remove some work directory (a subdirectory with name, started with WORK_DIRECTORY_PREFIX), and this directory is not locked via USAGE_MARKER_FILE_NAME file (i.e. it is not in use now), this method performs several attempts to remove the work directory, calling System.gc() between attempts. Usually it helps to release resources (like file mappings), which prevents from removing such unused subdirectories.

      Note: this method does not try to remove the directory tempDirectory itself.

      It is a good idea to call this method while starting your application and, maybe, after calling long-running external applications via execute(ProcessBuilder) method, to remove all "garbage" that was not deleted by normal calls of close() method in this or previous calls of your application.

      Parameters:
      tempDirectory - the path to the global disk directory for allocating temporary data; should be identical to the same argument of getInstance(ArrayContext, String, String) method, which you use for instantiation this object (or you may use cleanup() instead of this method, if you use getInstance(ArrayContext) method without the second argument).
      Returns:
      true if and only this method has successfully removed all subdirectories of the specified directory tempDirectory with names, started with WORK_DIRECTORY_PREFIX.
      Throws:
      NullPointerException - if tempDirectory argument is null.
      SecurityException - if System.getProperty("java.io.tmpdir") call throws this exception.
      See Also:
    • cleanup

      public static boolean cleanup()
      Equivalent to cleanup(getDefaultTempDirectory()). If you use getInstance(ArrayContext) method only and don't use getInstance(ArrayContext, String, String) with a custom second argument, you can use this method instead of cleanup(String).
      Returns:
      true if and only this method has successfully removed all subdirectories of getDefaultTempDirectory() with names, started with WORK_DIRECTORY_PREFIX.
      Throws:
      SecurityException - if System.getProperty("java.io.tmpdir") call throws this exception.
    • getDefaultTempDirectory

      public static String getDefaultTempDirectory()
      Returns the path to the default disk directory for storing temporary data: some "standard" subdirectory of the system temporary directory will be used. Namely, this method returns
       new File(System.getProperty("java.io.tmpdir"), TEMP_SUBDIRECTORY_DEFAULT_NAME).getPath()
       

      Note: this subdirectory is automatically created in getInstance(ArrayContext) method or in getInstance(ArrayContext, String, String) method, when its second argument is identical to the result of this method. However, this class never tries to remove this subdirectory: such an attempt could lead to errors if another application simultaneously tries to create this subdirectory. You may remove this subdirectory manually, for example, in the uninstaller of your software.

      Returns:
      the default disk directory for storing temporary data.
      Throws:
      SecurityException - if System.getProperty("java.io.tmpdir") call throws this exception.
      See Also:
    • getPropertyOrEnv

      public static String getPropertyOrEnv(String propertyKey, String envVarName)
      Returns the system property indicated by the specified key propertyKey, if it exists, or, if it is null, the environment variable indicated by the specified name envVarName. Equivalent to the following operator:
           System.getProperty(propertyKey) != null ? System.getProperty(propertyKey) : System.getenv(envVarName)
       

      This method is often used to specify parameters of the called external programs, such as a path to the called application, to provide user both mechanisms of customization (system properties and system environment).

      Parameters:
      propertyKey - the key, indicating the system property.
      envVarName - the name of the environment variable.
      Returns:
      the system property / environment variable with the given key / name; null, if there is no system property with the given key and also there is no environment variable with the given name.
      Throws:
      NullPointerException - if one of the arguments is null.
      IllegalArgumentException - if propertyKey is empty.
      SecurityException - when this exception was thrown by System.getProperty or System.getenv method.
      See Also:
    • getExistingPathFromPropertyOrEnv

      public static File getExistingPathFromPropertyOrEnv(String propertyKey, String envVarName, File defaultPath) throws FileNotFoundException
      Returns new File(getPropertyOrEnv(propertyKey,envVarName)), if such file or directory really exists, throws FileNotFoundException, if it does not exist, or returns defaultPath if it is not specified. More precisely, equivalent to the following:
           String s = getPropertyOrEnv(propertyKey, envVarName);
           File result = s != null ? new File(s) : defaultPath;
           if (result != null && !result.exists())
               throw new FileNotFoundException(some message);
           return result;
       

      Note: this method returns null in the only case, when getPropertyOrEnv method returns null (there is no system property with the given key and there is no environment variable with the given name) and, at the same time, defaultPath==null. If this method returns some non-null result, then there is a guarantee that it is an existing path, in terms of java.io.File.exists() method.

      This method is used for retrieving path to some disk file or directory, which must exist, for example, the path to an external executable program, which you want to call.

      Parameters:
      propertyKey - the key, indicating the system property.
      envVarName - the name of the environment variable.
      defaultPath - the path, returned when both the system property and the environment variable are not specified; may be null.
      Returns:
      the existing disk path, containing in the system property / environment variable with the given key / name, or null of there is no system property with the given key, there is no environment variable with the given name and defaultPath==null.
      Throws:
      NullPointerException - if propertyKey or envVarName argument is null.
      IllegalArgumentException - if propertyKey is empty.
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
      FileNotFoundException - if 1) the path, specified by the system property / environment variable, or 2) defaultPath if there is no such system property and environment variable, — does not correspond to an existing disk file or directory; note that in the 2nd case the exception is not thrown if defaultPath==null.
      See Also:
    • getExistingPathFromPropertyOrEnv

      public static File getExistingPathFromPropertyOrEnv(String propertyKey, String envVarName) throws FileNotFoundException
      Calls getExistingPathFromPropertyOrEnv(propertyKey,envVarName,null) and throws FileNotFoundException in a case of null result.

      This method may be used instead of getExistingPathFromPropertyOrEnv(String, String, File), if you require that either the specified system property, or the environment variable must be specified and contain a correct existing disk path.

      Parameters:
      propertyKey - the key, indicating the system property.
      envVarName - the name of the environment variable.
      Returns:
      the existing disk path, containing in the system property / environment variable with the given key / name; cannot be null.
      Throws:
      NullPointerException - if propertyKey or envVarName argument is null.
      IllegalArgumentException - if propertyKey is empty.
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
      FileNotFoundException - if some path is really specified by the system property / environment variable, but this path does not correspond to an existing disk file or directory, or if both System.getProperty and System.getenv method have returned null.
      See Also:
    • getCurrentJREHome

      public static File getCurrentJREHome()
      Returns path to the home directory of the currently executed JRE. Equivalent to the following:
           new File(System.getProperty("java.home"));
       

      Note: unlike getCustomJREHome(), here is no a strict guarantee that this method always returns an existing path. If the path, got from the system property "java.home", does not exists (very improbable situation), this method still returns it and does not throw FileNotFoundException.

      Note: if there is no system property "java.home" (also very improbable situation), i.e. if System.getProperty("java.home") returns null, this method throws InternalError.

      Returns:
      the home directory of the currently executed JRE,
      Throws:
      SecurityException - if this exception was thrown by System.getProperty.
      See Also:
    • getCustomJREHome

      public static File getCustomJREHome() throws FileNotFoundException
      Returns path to the home directory of some custom JRE, specified in JRE_PATH_PROPERTY_NAME system property or in JRE_PATH_ENV_NAME environment variable, or the home directory of the currently executed JVM if there is no such property / environment variable. Equivalent to the following:
           result = getExistingPathFromPropertyOrEnv(
               JRE_PATH_PROPERTY_NAME,
               JRE_PATH_ENV_NAME,
               getCurrentJREHome());
       

      Note: there is a guarantee that this method always returns an existing path, in terms of java.io.File.exists() method. If the path, got from system properties / environment, does not exists, this method throws FileNotFoundException.

      Returns:
      the home directory of the JRE, specified by JRE_PATH_PROPERTY_NAME / JRE_PATH_ENV_NAME, or the result of getCurrentJREHome() if it is not specified.
      Throws:
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
      FileNotFoundException - if getExistingPathFromPropertyOrEnv(java.lang.String, java.lang.String, java.io.File) method has thrown this exception.
      See Also:
    • getCustomJREHome

      public static File getCustomJREHome(String jreName) throws FileNotFoundException
      Extended analog of getCustomJREHome() method, allowing to specify some "name" of JRE, which is added as a suffix to the name of the corresponding system property or environment variable. It allows to use several different JREs, which you probably need in the same application. The typical recommended example of such usage is specifying the names "32" and "64": jreName="32" means that you need to work with 32-bit JRE, installed on the computer, jreName="64" means that you need to work with 64-bit JRE, installed on the computer, jreName=null means that the difference between JREs is not important and you need to work with some external JRE, globally customized for your application.

      More precisely, if jreName==null, this method is strictly equivalent to getCustomJREHome() method, and if jreName!=null, it is equivalent to the following:

           File namedHome = getExistingPathFromPropertyOrEnv(
               JRE_PATH_PROPERTY_NAME + "." + jreName,
               JRE_PATH_ENV_NAME + "_" + jreName,
               null);
           result = namedHome == null ? getCustomJREHome() : namedHome;
       

      For example, if jreName is "64", then this method will check existence of system property "net.algart.arrays.jre.path.64" and environment variable "NET_ALGART_ARRAYS_JVM_OPTIONS_64". If one of them exists, this method will check existence of the disk path (probably folder), specified by this system property / environment variable, and either will return this path (if it exists), or will throw FileNotFoundException (if there is no such disk folder or file). In other case, i.e. if both system property "net.algart.arrays.jre.path.64" and environment variable "NET_ALGART_ARRAYS_JRE_PATH_64" are not found, this method will call getCustomJREHome() method, which will try to find JRE home directory, specified in the system property "net.algart.arrays.jre.path" and environment variable "NET_ALGART_ARRAYS_JRE_PATH". If one of them exists, the method, analogously, will check existence of the disk path (probably folder), specified by this system property / environment variable, and either will return this path (if it exists), or will throw FileNotFoundException (if not). At last, if both system property "net.algart.arrays.jre.path" and environment variable "NET_ALGART_ARRAYS_JRE_PATH" are also not found, the current JVM home directory will be returned: System.getProperty("java.home") (also with the check of existence: if this property contains non-existing disk path, FileNotFoundException will be thrown).

      Note: there is a guarantee that this method always returns an existing path, in terms of java.io.File.exists() method. If the path, got from system properties / environment, does not exists, this method throws FileNotFoundException.

      Parameters:
      jreName - some internal "name" of the required JRE; typical values are "32" or "64"; may be null, then this method is equivalent to getCustomJREHome().
      Returns:
      the home directory of the JRE, specified by the corresponding system property or environment variable, or the result of getCustomJREHome() if it is not specified.
      Throws:
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
      FileNotFoundException - if getExistingPathFromPropertyOrEnv(java.lang.String, java.lang.String, java.io.File) or getCustomJREHome() method has thrown this exception.
    • getJavaExecutable

      public static File getJavaExecutable(File jreHome) throws FileNotFoundException
      Returns the path to the "java" executable utility ("java.exe" on Windows platform), located inside the specified JRE home directory. If this method fails to find java utility, it throws FileNotFoundException.

      Note: there is a guarantee that this method always returns an existing path, in terms of java.io.File.exists() method (when it does not throw FileNotFoundException).

      This method is useful when you want to execute an external program, written in Java: the result of this method should be passed as the first argument of the ProcessBuilder constructor.

      Parameters:
      jreHome - home directory of some JRE (for example, the result of getCurrentJREHome(), getCustomJREHome() or getCustomJREHome(String) method).
      Returns:
      the path to "java" executable program, starting JVM of the specified JRE.
      Throws:
      NullPointerException - if the argument is null.
      FileNotFoundException - if this method cannot find "java" utility.
      See Also:
    • getCustomJVMOptions

      public static List<String> getCustomJVMOptions()
      Returns the list of JVM options (arguments of "java" executable utility), listed in JVM_OPTIONS_PROPERTY_NAME system property or in JVM_OPTIONS_ENV_NAME environment variable, or null if there is no such property / environment variable. JVM options (command line arguments) should be separated by spaces in this system property / environment variable, and there should be no spaces inside each option (argument). This method is typically used together with getCustomJREHome().

      Equivalent to the following:

           String jvmOptions = getPropertyOrEnv(
               JVM_OPTIONS_PROPERTY_NAME,
               JVM_OPTIONS_ENV_NAME);
           result = jvmOptions == null ? null : java.util.Arrays.asList(jvmOptions.split("\\s+"));
       

      We recommend you to include this list into the arguments of the ProcessBuilder constructor, when you are going to execute an external Java program via Java machine, returned by getJavaExecutable(File) method.

      Returns:
      the list of JVM options, specified by JVM_OPTIONS_PROPERTY_NAME / JVM_OPTIONS_ENV_NAME, or null if it is not specified.
      Throws:
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
      See Also:
    • getCustomJVMOptions

      public static List<String> getCustomJVMOptions(String jreName)
      Extended analog of getCustomJVMOptions() method, allowing to specify some "name" of JRE, which is added as a suffix to the name of the corresponding system property or environment variable. It allows to use several settings for several JREs, which you probably need in the application. This method is typically used together with getCustomJREHome(String).

      More precisely, if jreName==null, this method is strictly equivalent to getCustomJVMOptions() method, and if jreName!=null, it is equivalent to the following:

           String jvmOptions = getPropertyOrEnv(
               JVM_OPTIONS_PROPERTY_NAME + "." + jreName,
               JVM_OPTIONS_ENV_NAME + "_" + jreName);
           result = jvmOptions == null ? getCustomJVMOptions() : java.util.Arrays.asList(jvmOptions.split("\\s+"));
       

      For example, if jreName is "64", then this method will check existence of system property "net.algart.arrays.jvm.options.64" and environment variable "NET_ALGART_ARRAYS_JVM_OPTIONS_64". If one of them exists, it will be parsed and returned; in other case, this method will call getCustomJVMOptions().

      Parameters:
      jreName - some internal "name" of the required JRE; typical values are "32" or "64"; may be null, then this method is equivalent to getCustomJVMOptions().
      Returns:
      the list of JVM options, specified by the corresponding system property or environment variable, or the result of getCustomJVMOptions() if it is not specified.
      Throws:
      SecurityException - if this exception was thrown by System.getProperty or System.getenv method.
    • writeUTF8

      public static void writeUTF8(File file, String text) throws IOException
      Writes the given text into the file in UTF-8 encoding. The file is fully rewritten and will contain this text only.
      Parameters:
      file - the file which should be written.
      text - some text data, which will be saved into this file.
      Throws:
      IOException - if an I/O error occurs.
      See Also:
    • readUTF8

      public static String readUTF8(File file) throws IOException
      Reads the full content of the given text file and returns it as a String. This file is supposed to be written in UTF-8 encoding.
      Parameters:
      file - the file which should be read.
      Returns:
      the full text content of this file.
      Throws:
      IOException - if an I/O error occurs.
      See Also:
    • createTempDirectory

      public static File createTempDirectory(File parentDirectory, String prefix) throws IOException

      Creates a new empty unique subdirectory within the specified parent directory, using the given prefix to generate its name. It is an analog of java.io.File.createTempFile method, but creates a subdirectory, not a file.

      The created subdirectory will be the following:

           new java.io.File(parentDirectory, prefix + String.valueOf(n))
       
      where n is some positive long integer value, initialized to some random value while the first call of this method and corrected while each new call. This subdirectory is created by java.io.File.mkdir() method; in a case of failure, several attemps are performed.
      Parameters:
      parentDirectory - some parent directory; unlike java.io.File.createTempFile method, null is not allowed here.
      prefix - the prefix string; unlike java.io.File.createTempFile method, here is no requirements for its length
      Returns:
      new unique subdirectory of parentDirectory, created by this method.
      Throws:
      NullPointerException - if prefix or parentDirectory argument is null.
      IOException - if a new subdirectory cannot be created.
    • context

      public ArrayContext context()
      Returns the current context used by this instance for some operations. This context is specified while creating an instance of this class.

      The context is used in execute(ProcessBuilder) method to allow the user to interrupt it. Namely, if the context is not null, execute(ProcessBuilder) method periodically calls context.checkInterruption(), and if some exception is thrown, terminates the external process by java.lang.Process.destroy().

      Specified by:
      context in interface ArrayProcessor
      Returns:
      the current context used by this instance; may be null.
    • getWorkDirectory

      public File getWorkDirectory()
      Returns the work directory of this processor, created by getInstance(ArrayContext, String, String) or getInstance(ArrayContext) method. See getInstance(ArrayContext, String, String) method about "work directory" concept.

      The returned object contains an absolute path: File.getAbsoluteFile().

      Returns:
      the work directory of this processor.
      See Also:
    • getWorkFile

      public File getWorkFile(String childFileName)
      Equivalent to new File(getWorkDirectory(), childFileName).
      Parameters:
      childFileName - the child file name.
      Returns:
      new File instance, describing the given file inside the work directory of this object.
      See Also:
    • writeWorkUTF8

      public void writeWorkUTF8(String childFileName, String text) throws IOException
      Equivalent to writeUTF8(getWorkFile(childFileName),text).

      It is a useful method for inter-application communication with the called external program.

      Parameters:
      childFileName - the name of the file inside the work directory of this object.
      text - some text data, which will be saved into this file.
      Throws:
      IOException - if an I/O error occurs.
    • readWorkUTF8

      public String readWorkUTF8(String childFileName) throws IOException
      Equivalent to readUTF8(getWorkFile(childFileName)).

      It is a useful method for inter-application communication with the called external program.

      Parameters:
      childFileName - the name of the file inside the work directory of this object.
      Returns:
      the full text content of this file.
      Throws:
      IOException - if an I/O error occurs.
    • getOutputStream

      public OutputStream getOutputStream()
      Returns the output stream, set by setOutputStream(java.io.OutputStream) method and used by execute method for duplication of the output stream of an external program. The default value is null — it is returned if setOutputStream(java.io.OutputStream) was never called.
      Returns:
      the current output stream, used by execute method for duplication of the output stream of an external program.
    • setOutputStream

      public void setOutputStream(OutputStream outputStream)
      Sets the stream for duplication of the output stream of an external program. If you set some non-null stream by this method, then the execute(ProcessBuilder) method will duplicate each line, written to the standard OS output stream by the called program, into this stream.
      Parameters:
      outputStream - the output stream for duplication of the standard OS output stream of external programs; may be null, then it will be ignored.
      See Also:
    • getErrorStream

      public OutputStream getErrorStream()
      Returns the error stream, set by setErrorStream(java.io.OutputStream) method and used by execute method for duplication of the error stream of an external program. The default value is null — it is returned if setErrorStream(java.io.OutputStream) was never called.
      Returns:
      the current error stream, used by execute method for duplication of the error stream of an external program.
    • setErrorStream

      public void setErrorStream(OutputStream errorStream)
      Sets the stream for duplication of the error stream of an external program. If you set some non-null stream by this method, then the execute(ProcessBuilder) method will duplicate each line, written to the standard OS error stream by the called program, into this stream.

      Note: even when this stream is null (default value), if the called program was finished unsuccessfully, i.e. with non-zero OS exit code, you can get the full content of the error stream of the called program by getExternalProcessErrorMessage() method of the ExternalProcessException, thrown by execute(ProcessBuilder) method.

      Parameters:
      errorStream - the output stream for duplication of the standard OS error stream of external programs; may be null, then it will be ignored.
      See Also:
    • setSystemStreams

      public void setSystemStreams()
      Equivalent to two calls: setOutputStream(System.out) and setErrorStream(System.err).
    • execute

      public void execute(ProcessBuilder processBuilder) throws IOException
      Executes the external program by process=processBuilder.start() call and waits until it will terminate by process.waitFor() call. In addition to these main actions, this method:
       

      Note: this method cannot be used after closing this object by close() method.

      Note: if writing into the streams, set by setOutputStream(java.io.OutputStream) or setErrorStream(java.io.OutputStream) methods, lead to IOException, this exception is ignored.

      Parameters:
      processBuilder - the process builder, which will used for calling external application (by processBuilder.start() call).
      Throws:
      IOException - if processBuilder.start() has thrown this exception, or if process.waitFor() has returned non-zero result (it will be ExternalProcessException in the last case).
      IllegalStateException - if close() method of this instance was already called.
      RuntimeException - this method also can throw all runtime exceptions, which are thrown by processBuilder.start() call.
    • cancelRemovingWorkDirectory

      public void cancelRemovingWorkDirectory()
      Cancels automatic removing of the work directory, created while instantiation of this object, in close() method. If you call this method at least once, then the further call of close() will just set the state of this instance to "successfully closed" and will not try to remove the temporary disk data, which you possibly used for exchanging information with an external program. It can be useful for debugging needs.

      Note that this method does not cancel removing data, performed by cleanup() and cleanup(String) methods.

    • isRemovingWorkDirectoryCancelled

      public boolean isRemovingWorkDirectoryCancelled()
      Returns true if and only if the method cancelRemovingWorkDirectory() was called at least once.
      Returns:
      whether automatic removing of the work directory is cancelled by cancelRemovingWorkDirectory() method.
    • close

      public void close()
      Tries to fully (recursively) remove the work directory, created while instantiation of this object (if this action was not cancelled by cancelRemovingWorkDirectory() call), and sets the state of this instance to "closed". See getInstance(ArrayContext, String, String) method about "work directory" concept.

      You must call this method after finishing usage of this object. We strongly recommend you to call it in the finally section of your code. After this call, you cannot use execute(ProcessBuilder) method, though can use other methods — in particular, you can call this method again.

      There is no guarantee that this method successfully removes the work directory. This method can fail, for example, when some temporary files, used for exchanging data with an external program, are locked by OS, and we cannot unlock them immediately after termination of the external program — it can be connected with file mapping (in particular, mapping via LargeMemoryModel, which is unmapped in Java while garbage collection only).

      If this method has successfully removed the work directory or if the removing was cancelled by cancelRemovingWorkDirectory() call, then isClosedSuccessfully() method will return true, and further calls of this method do nothing. If this method was not able to remove all content of the work directory, isClosedSuccessfully() method will return false. In this case, you may try to call this method again after some time or after a call of System.gc(). In any case, after the first call of this method, isClosed() method returns true and execute(ProcessBuilder) method throws IllegalStateException.

      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      See Also:
    • isClosed

      public boolean isClosed()
      Returns true if this instance is "closed", i.e. if close() method was called at least once. You cannot call execute(ProcessBuilder) method for closed objects — it will throw IllegalStateException.
      Returns:
      whether this object is already closed and, so, cannot be used for calling external programs.
      See Also:
    • isClosedSuccessfully

      public boolean isClosedSuccessfully()
      Returns true if this instance is "closed" and all its temporary data were successfully removed, i.e. if close() method was called and it has successfully removed the work directory of this object. If automatic removing of the work directory was cancelled by cancelRemovingWorkDirectory() method, then call of this method usually returns true after close() (though the temporary data were not removed). If this method returns true, then isClosed() method also returns true.
      Returns:
      whether this object is already closed and its work directory is successfully completely removed.
    • toString

      public String toString()
      Returns a brief string description of this factory.

      The result of this method may depend on implementation.

      Overrides:
      toString in class Object
      Returns:
      a brief string description of this object.