001package Torello.Java;
002
003import java.io.File;
004import java.util.Map;
005import java.util.function.Consumer;
006
007/**
008 * This class allows for the user to provide redirects, environment variables, and output/error
009 * unification (meaning the Standard-Output and Error-Output Streams are printed together, as if
010 * they were being printed to the terminal).
011 * 
012 * <EMBED CLASS='external-html' DATA-FILE-ID=OSEXTRAS>
013 */
014@SuppressWarnings("overrides") // The 'equals(other) causes a warning about hashCode
015public class OSExtras implements Cloneable
016{
017    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_CUR_WDIR> */
018    public File currentWorkingDirectory = null;
019
020    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_MERGE_IE> */
021    public boolean mergeStdErrorAndStdOut = false;
022
023    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_OUT_REDIR> */
024    public ProcessBuilder.Redirect outputRedirect = null;
025
026    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_INP_REDIR> */
027    public ProcessBuilder.Redirect inputRedirect = null;
028
029    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_ERR_REDIR> */
030    public ProcessBuilder.Redirect errorRedirect = null;
031
032    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_ENV_UPDT> */
033    public Consumer<Map<String, String>> environmentVariableUpdater = null;
034
035    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_JAVA_PIPE> */
036    public OSJavaPipe javaPipe = null;
037
038    /** Builds a new instance of this class, and keeps the default values assigned. */
039    public OSExtras() { }
040
041    /**
042     * Constructs an instance of this class
043     * @param currentWorkingDirectory       <EMBED CLASS=external-html DATA-FILE-ID=OSE_CUR_WDIR>
044     * @param mergeStdErrorAndStdOut        <EMBED CLASS=external-html DATA-FILE-ID=OSE_MERGE_IE>
045     * @param outputRedirect                <EMBED CLASS=external-html DATA-FILE-ID=OSE_OUT_REDIR>
046     * @param inputRedirect                 <EMBED CLASS=external-html DATA-FILE-ID=OSE_INP_REDIR>
047     * @param errorRedirect                 <EMBED CLASS=external-html DATA-FILE-ID=OSE_ERR_REDIR>
048     * @param environmentVariableUpdater    <EMBED CLASS=external-html DATA-FILE-ID=OSE_ENV_UPDT>
049     * @param javaPipe                      <EMBED CLASS=external-html DATA-FILE-ID=OSE_JAVA_PIPE>
050     * 
051     * @throws IllegalArgumentException if {@code inputRedirect} and {@code javaPipe} are both
052     * non-null.  Input may be redirected from only a single location.  Neither of these parameters
053     * are required, but at most - <I>only one of these two parameters may be passed a non-null
054     * value, otherwise this exception shall throw!</I>
055     */
056    public OSExtras(
057           File                            currentWorkingDirectory,
058           boolean                         mergeStdErrorAndStdOut,
059           ProcessBuilder.Redirect         outputRedirect,
060           ProcessBuilder.Redirect         inputRedirect,
061           ProcessBuilder.Redirect         errorRedirect,
062           Consumer<Map<String, String>>   environmentVariableUpdater,
063           OSJavaPipe                      javaPipe
064        )
065    {
066        this.currentWorkingDirectory    = currentWorkingDirectory;
067        this.mergeStdErrorAndStdOut     = mergeStdErrorAndStdOut;
068        this.outputRedirect             = outputRedirect;
069        this.inputRedirect              = inputRedirect;
070        this.errorRedirect              = errorRedirect;
071        this.environmentVariableUpdater = environmentVariableUpdater;
072        this.javaPipe                   = javaPipe;
073
074        if ((this.javaPipe != null) && (this.inputRedirect != null))
075
076            throw new IllegalArgumentException(
077                "You have passed non-null Object-References to both parameters [inputRedirect] " +
078                "and to [javaPipe], but this is not allowed.  Neither of these parameter are " +
079                "actually required, and at most, only one of them are permitted non-null values."
080            );
081    }
082
083
084    // ********************************************************************************************
085    // ********************************************************************************************
086    // Object & Cloneable Methods
087    // ********************************************************************************************
088    // ********************************************************************************************
089
090
091    private static String toStrApp(Object a)
092    { return (a == null) ? "null\n" : (a.getClass().getName() + '\n'); }
093
094    /**
095     * Generates a {@code String} this class.  The returned {@code String} merely encodes the
096     * class-names of the non-null fields.
097     *     
098     * @return A simple representation of this class, as a {@code java.lang.String}
099     */
100    public String toString()
101    {
102        // private static String toStrApp(Appendable a)
103        // { return (a == null) ? "null\n" : (a.getClass().getName() + '\n'); }
104
105        return
106            "currentWorkingDirectory:    " + toStrApp(this.currentWorkingDirectory) +
107            "mergeStdErrorAndStdOut:     " + this.mergeStdErrorAndStdOut + '\n' +
108            "outputRedirect:             " + toStrApp(this.outputRedirect) +
109            "inputRedirect:              " + toStrApp(this.inputRedirect) +
110            "errorRedirect:              " + toStrApp(this.errorRedirect) +
111            "environmentVariableUpdater: " + toStrApp(this.environmentVariableUpdater) +
112            "javaPipe:                   " + ((this.javaPipe == null) ? "null\n" : StrPrint.abbrev
113                                                (this.javaPipe.toString(), 30, true, null, 60));
114    }
115
116    /**
117     * Checks for equality based on whether two instances have identical references.
118     *
119     * @param other Any Java Object.  Only a valid sub-class of {@code OSExtras} could possibly
120     * produce a {@code TRUE} return value
121     *
122     * @return {@code TRUE} if and only if each of the {@code OSExtras} fields are <I>identical
123     * references in both {@code 'this'} and {@code 'other'}</I>.
124     */
125    public boolean equals(Object other)
126    {
127        if (other == null) return false;
128
129        if (! OSExtras.class.isAssignableFrom(other.getClass())) return false;
130
131        OSExtras o = (OSExtras) other;
132
133        return 
134                (this.currentWorkingDirectory       == o.currentWorkingDirectory)
135            &&  (this.mergeStdErrorAndStdOut        == o.mergeStdErrorAndStdOut)
136            &&  (this.outputRedirect                == o.outputRedirect)
137            &&  (this.inputRedirect                 == o.inputRedirect)
138            &&  (this.errorRedirect                 == o.errorRedirect)
139            &&  (this.environmentVariableUpdater    == o.environmentVariableUpdater)
140            &&  (this.javaPipe                      == o.javaPipe);
141    }
142
143    /**
144     * Makes a copy of {@code 'this'} instance and returns it.
145     * @return a clone of {@code 'this'} instance
146     */
147    public Object clone()
148    {
149        return new OSExtras(
150            this.currentWorkingDirectory,
151            this.mergeStdErrorAndStdOut,
152            this.outputRedirect,
153            this.inputRedirect,
154            this.errorRedirect,
155            this.environmentVariableUpdater,
156            this.javaPipe
157        );
158    }
159}