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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | package Torello.Java; import java.io.BufferedWriter; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.InputStream; import java.io.IOException; import java.util.Arrays; import java.util.Objects; /** * Allows a user to pipe data directly from Java-Memory, and into an instance of * <CODE>java.lang.Process</CODE>. */ public class OSJavaPipe implements Cloneable { // ******************************************************************************************** // ******************************************************************************************** // Two Private-Fields, Two Inpsection Methods // ******************************************************************************************** // ******************************************************************************************** private Object textOrDataToPipe; private byte dataType; /** * Retrieve the Data-Type that is contained by this instance' internal PIPE-Data contents. * @return The Static-Flag Constant associated with the Data-Type that has been assigned to * this instance. */ public byte getDataType() { return this.dataType; } /** * Retrieve the actual data, as a {@code java.lang.Object} contained by this instance. * @return This class internal Data-Field */ public Object getPipeData() { return this.textOrDataToPipe; } // ******************************************************************************************** // ******************************************************************************************** // Static-Flag Constants, representing the Data's Type // ******************************************************************************************** // ******************************************************************************************** /** * Constant used to indicate that this class data-contents currently contain a non-null * {@code int[]}-Array. */ public static final byte INT_ARR = 1; /** * Constant used to indicate that this class data-contents currently contain a non-null * {@code byte[]}-Array. */ public static final byte BYTE_ARR = 2; /** * Constant used to indicate that this class data-contents currently contain a non-null * {@code char[]}-Array. */ public static final byte CHAR_ARR = 3; /** * Constant used to indicate that this class data-contents currently contain a non-null * {@code String}. */ public static final byte STRING = 4; /** * Constant used to indicate that this class data-contents currently contain a non-null * {@code InputStream}. */ public static final byte INPUT_STREAM = 5; // ******************************************************************************************** // ******************************************************************************************** // Constructors // ******************************************************************************************** // ******************************************************************************************** private OSJavaPipe() { } /** * Constructs an instance of this class, assigning the input {@code int[]}-Array Parameter to * the internal Data-Field. * * @param intArrData Any Java {@code int[]} Integer-Array. * @throws NullPointerException if {@code 'intArrData'} is null. */ public OSJavaPipe(final int[] intArrData) { this.setData(intArrData); } /** * Constructs an instance of this class, assigning the input {@code byte[]}-Array Parameter to * the internal Data-Field. * * @param byteArrData Any Java {@code byte[]} Byte-Array. * @throws NullPointerException if {@code 'byteArrData'} is null. */ public OSJavaPipe(final byte[] byteArrData) { this.setData(byteArrData); } /** * Constructs an instance of this class, assigning the input {@code char[]}-Array Parameter to * the internal Data-Field. * * @param charArrData Any Java {@code char[]} Char-Array. * @throws NullPointerException if {@code 'charArrData'} is null. */ public OSJavaPipe(final char[] charArrData) { this.setData(charArrData); } /** * Constructs an instance of this class, assigning the input {@code String}-Parameter to the * internal Data-Field. * * @param strData Any Java {@code String}. * @throws NullPointerException if {@code 'strData'} is null. */ public OSJavaPipe(final String strData) { this.setData(strData); } /** * Constructs an instance of this class, assigning the {@code InputStream} Parameter to the * internal Data-Field. * * @param inputStream Any Java Input-Stream. * @throws NullPointerException if {@code 'inputStream'} is null. */ public OSJavaPipe(final InputStream inputStream) { this.setData(inputStream); } // ******************************************************************************************** // ******************************************************************************************** // This Class Main User-API for assigning some data // ******************************************************************************************** // ******************************************************************************************** /** * Sets the data to be used for piping into an Operating-System Process. * @param intArrData Any Java {@code int[]} Integer-Array. * @throws NullPointerException if {@code 'intArrData'} is null. */ public synchronized void setData(final int[] intArrData) { Objects.requireNonNull(intArrData, "The int[]-Array passed may not be null"); this.textOrDataToPipe = intArrData; this.dataType = INT_ARR; } /** * Sets the data to be used for piping into an Operating-System Process. * @param byteArrData Any Java {@code byte[]} Byte-Array. * @throws NullPointerException if {@code 'byteArrData'} is null. */ public synchronized void setData(final byte[] byteArrData) { Objects.requireNonNull(byteArrData, "The byte[]-Array passed may not be null"); this.textOrDataToPipe = byteArrData; this.dataType = BYTE_ARR; } /** * Sets the data to be used for piping into an Operating-System Process. * @param charArrData Any Java {@code char[]} Char-Array. * @throws NullPointerException if {@code 'charArrData'} is null. */ public synchronized void setData(final char[] charArrData) { Objects.requireNonNull(charArrData, "The char[]-Array passed may not be null"); this.textOrDataToPipe = charArrData; this.dataType = CHAR_ARR; } /** * Sets the data to be used for piping into an Operating-System Process. * @param strData Any Java {@code String}. * @throws NullPointerException if {@code 'strData'} is null. */ public synchronized void setData(final String strData) { Objects.requireNonNull(strData, "The String-Data passed may not be null"); this.textOrDataToPipe = strData; this.dataType = STRING; } /** * Sets the data to be used for piping into an Operating-System Process. * @param inputStream Any Java Input-Stream. * @throws NullPointerException if {@code 'inputStream'} is null. */ public synchronized void setData(final InputStream inputStream) { Objects.requireNonNull(inputStream, "The Input-Stream passed may not be null"); this.textOrDataToPipe = inputStream; this.dataType = INPUT_STREAM; } // ******************************************************************************************** // ******************************************************************************************** // Package-Private Method for writing this data to an input stream. // ******************************************************************************************** // ******************************************************************************************** // Class OSCommands uses this Package-Private method to write the contents of the data-field // inside this class to the "OutputStream". The OutputStream instance that is provided as // input to this method is the one that is retrieved by invoking the method: // // Process.getOutputStream(). // // This OutputStream pipes the text/data that it receives directly to the Operating-System's // Process. NOTE - this method is, essentially, the whole entire purpose of this class. Also, // this class isn't so complicated, it's just a lot of wordy-explanations that help understand // how to use java.lang.Process / Process.Redirect / and all those Input-Output Streams. It // hopefully makes it a lot easier to use and extend this stuff. It certainly does for me. // // Again, this is Package-Private, and only invoked in one place, inside the "OSCommands" // method. synchronized void writeToPipe(final OutputStream os) throws IOException { switch (this.dataType) { case INT_ARR : for (int i : (int[]) textOrDataToPipe) os.write(i); break; case BYTE_ARR : for (byte b : (byte[]) textOrDataToPipe) os.write(b); break; case CHAR_ARR : for (char c : (char[]) textOrDataToPipe) os.write(c); break; case STRING : BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os)); writer.write((String) textOrDataToPipe); writer.flush(); writer.close(); // Important to close the stream to signal end of input break; case INPUT_STREAM : ((InputStream) textOrDataToPipe).transferTo(os); break; default: throw new UnreachableError(); } os.flush(); os.close(); } // ******************************************************************************************** // ******************************************************************************************** // java.lang.Object // ******************************************************************************************** // ******************************************************************************************** private static final String NAME = "OSJavaPipe Contents: "; /** * Generates a {@code String} this class. The returned {@code String} merely converts the * contained data to a {@code String}, using Standard Java Methods. * * @return A simple representation of this class, as a {@code java.lang.String} */ public synchronized String toString() { switch (this.dataType) { case INT_ARR : return NAME + "int[]:\n" + StrPrint.abbrev( Arrays.toString((int[]) this.textOrDataToPipe), 60, true, null, 120 ); case BYTE_ARR : return NAME + "byte[]:\n" + StrPrint.abbrev( Arrays.toString((byte[]) this.textOrDataToPipe), 60, true, null, 120 ); case CHAR_ARR : return NAME + "char[]:\n" + StrPrint.abbrev( Arrays.toString((char[]) this.textOrDataToPipe), 60, true, null, 120 ); case STRING : return NAME + "String:\n" + StrPrint.abbrev ((String) this.textOrDataToPipe, 60, true, null, 120); case INPUT_STREAM : return NAME + "InputStream: Non-Null Data-Input\n"; default: throw new UnreachableError(); } } /** * Checks for equality based on whether two instances have identical references. * * @param other Any Java Object. Only a valid sub-class of {@code OSJavaPipe} could possibly * produce a {@code TRUE} return value * * @return {@code TRUE} if and only if this class' internal fields are <I>identical * references in both {@code 'this'} and {@code 'other'}</I>. */ public synchronized boolean equals(Object other) { if (other == null) return false; if (! (other instanceof OSJavaPipe)) return false; final OSJavaPipe o = (OSJavaPipe) other; return Objects.equals(this.textOrDataToPipe, o.textOrDataToPipe) && (this.dataType == o.dataType); } /** * Makes a copy of {@code 'this'} instance and returns it. * @return a clone of {@code 'this'} instance */ public synchronized Object clone() { // Private-Internal Zero-Argument Constructor OSJavaPipe ret = new OSJavaPipe(); ret.dataType = this.dataType; ret.textOrDataToPipe = this.textOrDataToPipe; return ret; } /** * Produces a Hash-Code that may be used to place this instance-reference into a Hash-Table, * Set or Map. The code produced is generated using whatever hash-code value is returned * by this class' internal {@link #textOrDataToPipe} hash-code method. * * @return a hashcode */ public int hashCode() { return this.textOrDataToPipe.hashCode(); } } |