1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package Torello.Java;

import java.io.File;
import java.util.Map;
import java.util.function.Consumer;

/**
 * This class allows for the user to provide redirects, environment variables, and output/error
 * unification (meaning the Standard-Output and Error-Output Streams are printed together, as if
 * they were being printed to the terminal).
 * 
 * <EMBED CLASS='external-html' DATA-FILE-ID=OSEXTRAS>
 */
@SuppressWarnings("overrides") // The 'equals(other) causes a warning about hashCode
public class OSExtras implements Cloneable
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_CUR_WDIR> */
    public File currentWorkingDirectory = null;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_MERGE_IE> */
    public boolean mergeStdErrorAndStdOut = false;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_OUT_REDIR> */
    public ProcessBuilder.Redirect outputRedirect = null;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_INP_REDIR> */
    public ProcessBuilder.Redirect inputRedirect = null;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_ERR_REDIR> */
    public ProcessBuilder.Redirect errorRedirect = null;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_ENV_UPDT> */
    public Consumer<Map<String, String>> environmentVariableUpdater = null;

    /** <EMBED CLASS='external-html' DATA-FILE-ID=OSE_JAVA_PIPE> */
    public OSJavaPipe javaPipe = null;

    /** Builds a new instance of this class, and keeps the default values assigned. */
    public OSExtras() { }

    /**
     * Constructs an instance of this class
     * @param currentWorkingDirectory       <EMBED CLASS=external-html DATA-FILE-ID=OSE_CUR_WDIR>
     * @param mergeStdErrorAndStdOut        <EMBED CLASS=external-html DATA-FILE-ID=OSE_MERGE_IE>
     * @param outputRedirect                <EMBED CLASS=external-html DATA-FILE-ID=OSE_OUT_REDIR>
     * @param inputRedirect                 <EMBED CLASS=external-html DATA-FILE-ID=OSE_INP_REDIR>
     * @param errorRedirect                 <EMBED CLASS=external-html DATA-FILE-ID=OSE_ERR_REDIR>
     * @param environmentVariableUpdater    <EMBED CLASS=external-html DATA-FILE-ID=OSE_ENV_UPDT>
     * @param javaPipe                      <EMBED CLASS=external-html DATA-FILE-ID=OSE_JAVA_PIPE>
     * 
     * @throws IllegalArgumentException if {@code inputRedirect} and {@code javaPipe} are both
     * non-null.  Input may be redirected from only a single location.  Neither of these parameters
     * are required, but at most - <I>only one of these two parameters may be passed a non-null
     * value, otherwise this exception shall throw!</I>
     */
    public OSExtras(
           File                            currentWorkingDirectory,
           boolean                         mergeStdErrorAndStdOut,
           ProcessBuilder.Redirect         outputRedirect,
           ProcessBuilder.Redirect         inputRedirect,
           ProcessBuilder.Redirect         errorRedirect,
           Consumer<Map<String, String>>   environmentVariableUpdater,
           OSJavaPipe                      javaPipe
        )
    {
        this.currentWorkingDirectory    = currentWorkingDirectory;
        this.mergeStdErrorAndStdOut     = mergeStdErrorAndStdOut;
        this.outputRedirect             = outputRedirect;
        this.inputRedirect              = inputRedirect;
        this.errorRedirect              = errorRedirect;
        this.environmentVariableUpdater = environmentVariableUpdater;
        this.javaPipe                   = javaPipe;

        if ((this.javaPipe != null) && (this.inputRedirect != null))

            throw new IllegalArgumentException(
                "You have passed non-null Object-References to both parameters [inputRedirect] " +
                "and to [javaPipe], but this is not allowed.  Neither of these parameter are " +
                "actually required, and at most, only one of them are permitted non-null values."
            );
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Object & Cloneable Methods
    // ********************************************************************************************
    // ********************************************************************************************


    private static String toStrApp(Object a)
    { return (a == null) ? "null\n" : (a.getClass().getName() + '\n'); }

    /**
     * Generates a {@code String} this class.  The returned {@code String} merely encodes the
     * class-names of the non-null fields.
     *     
     * @return A simple representation of this class, as a {@code java.lang.String}
     */
    public String toString()
    {
        // private static String toStrApp(Appendable a)
        // { return (a == null) ? "null\n" : (a.getClass().getName() + '\n'); }

        return
            "currentWorkingDirectory:    " + toStrApp(this.currentWorkingDirectory) +
            "mergeStdErrorAndStdOut:     " + this.mergeStdErrorAndStdOut + '\n' +
            "outputRedirect:             " + toStrApp(this.outputRedirect) +
            "inputRedirect:              " + toStrApp(this.inputRedirect) +
            "errorRedirect:              " + toStrApp(this.errorRedirect) +
            "environmentVariableUpdater: " + toStrApp(this.environmentVariableUpdater) +
            "javaPipe:                   " + ((this.javaPipe == null) ? "null\n" : StrPrint.abbrev
                                                (this.javaPipe.toString(), 30, true, null, 60));
    }

    /**
     * Checks for equality based on whether two instances have identical references.
     *
     * @param other Any Java Object.  Only a valid sub-class of {@code OSExtras} could possibly
     * produce a {@code TRUE} return value
     *
     * @return {@code TRUE} if and only if each of the {@code OSExtras} fields are <I>identical
     * references in both {@code 'this'} and {@code 'other'}</I>.
     */
    public boolean equals(Object other)
    {
        if (other == null) return false;

        if (! OSExtras.class.isAssignableFrom(other.getClass())) return false;

        OSExtras o = (OSExtras) other;

        return 
                (this.currentWorkingDirectory       == o.currentWorkingDirectory)
            &&  (this.mergeStdErrorAndStdOut        == o.mergeStdErrorAndStdOut)
            &&  (this.outputRedirect                == o.outputRedirect)
            &&  (this.inputRedirect                 == o.inputRedirect)
            &&  (this.errorRedirect                 == o.errorRedirect)
            &&  (this.environmentVariableUpdater    == o.environmentVariableUpdater)
            &&  (this.javaPipe                      == o.javaPipe);
    }

    /**
     * Makes a copy of {@code 'this'} instance and returns it.
     * @return a clone of {@code 'this'} instance
     */
    public Object clone()
    {
        return new OSExtras(
            this.currentWorkingDirectory,
            this.mergeStdErrorAndStdOut,
            this.outputRedirect,
            this.inputRedirect,
            this.errorRedirect,
            this.environmentVariableUpdater,
            this.javaPipe
        );
    }
}