Class RemoteProcess
- All Implemented Interfaces:
AutoCloseable
CommandRequest.start() — the streaming counterpart
of CommandRequest.execute(), shaped like Process. Output can be
consumed while the command is still running:
try (RemoteProcess process = client.command("wevtutil qe System /f:text").start()) {
try (BufferedReader out = process.stdout()) {
out.lines().forEach(System.out::println);
}
int exitCode = process.waitFor();
}
Lifecycle. The process owns the client's serial connection until the command completes or
the process is closed: other operations on the same client block in the meantime (the same
contract as a JDBC ResultSet on its connection). Closing before completion sends the
WinRM terminate Signal, which stops the remote command. Always close the process — use
try-with-resources. Closing the readers returned by stdout()/stderr() does
not close the process.
Reading. Both channels are fed by the same WSMan Receive loop: reading either channel (or
calling waitFor()) advances the loop, and output that arrives for the channel not being
read is buffered in memory until it is read — so memory is bounded by the unread channel, not by
the total output. Output is decoded incrementally with the request's charset; a multibyte
character split across protocol chunks is decoded correctly.
Timeout. The request timeout acts as an inactivity timeout: the longest silence
tolerated from the server between two responses, not an overall deadline — a command may run
(and stream) far longer than the timeout as long as it keeps producing output. Reads and waits
throw WinRMTimeoutException when the command stays silent for a whole timeout; use
waitFor(Duration) for an overall deadline.
Writing. stdin() feeds the command's standard input: flush() carries the
written text to the host as a WSMan Send, close() marks the end of input (the remote
stdin then reaches EOF). Writes and reads alternate on the caller's thread, exactly like
Process pipes — including the classic deadlock, which is the caller's to
avoid: blocking on a read while the remote command itself is blocked waiting for input (or the
reverse) hangs both sides until the inactivity timeout fires.
Threading. A process is not thread-safe: read, write, wait and close from one thread at a time.
Failures during consumption are reported through the unchecked
WinRMClientException hierarchy, including from the
readers' read() methods.
-
Method Summary
Modifier and TypeMethodDescriptionvoidclose()Terminate the command (when it is still running) and release the client's connection.intexitCode()Get the exit code of the completed command.voidInterrupt the command the way a console Ctrl+C would — the WSManctrl_cSignal.booleanAdvance the stream by at most one bounded protocol round trip: ask the server to answer within the given wait — with output when it has any, with the protocol's "nothing yet" otherwise — buffer whatever arrives for the readers, and report whether the command has completed.stderr()Get the standard error of the remote command, decoded incrementally: lines can be read while the command is still running.stdin()Get the standard input of the remote command.stdout()Get the standard output of the remote command, decoded incrementally: lines can be read while the command is still running.intwaitFor()booleanWait at most the given duration for the command to complete — an overall deadline, on top of the per-response inactivity timeout.
-
Method Details
-
stdout
Get the standard output of the remote command, decoded incrementally: lines can be read while the command is still running. Always the same reader instance; closing it does not affect the process.- Returns:
- the standard output reader
-
stderr
Get the standard error of the remote command, decoded incrementally: lines can be read while the command is still running. Always the same reader instance; closing it does not affect the process.- Returns:
- the standard error reader
-
stdin
Get the standard input of the remote command. Written text is buffered locally untilflush(), which carries it to the host as one WSMan Send (encoded with the request's charset);close()sends the final chunk flagged as the end of input, after which the remote stdin reaches EOF. Always the same writer instance; closing it does not close the process — but unlike the readers it does talk to the host, so close it before (or via) the process itself, not after.When the request pre-supplied the input (
stdin(...)on the builder), that input was already delivered in full: this writer is then closed from the start.A command that must observe the EOF — a filter like
sortthat only acts once its input ends — needs pipe semantics: declare the interactive input with the no-argumentCommandRequest.stdin()on the builder. Without it the remote stdin keeps the historical console semantics, where writes are delivered but the end of input is not.Failures while sending are reported through the unchecked
WinRMClientExceptionhierarchy; writing after the end of input or after the command completed throwsIllegalStateException.- Returns:
- the standard input writer
-
interrupt
public void interrupt()Interrupt the command the way a console Ctrl+C would — the WSManctrl_cSignal. It interrupts the command's child process without terminating the command or this process handle: the process stays fully usable, which is what an interactive session needs. A no-op once the command has completed or the process is closed.- Throws:
WinRMTimeoutException- when the server does not answer the Signal in timeWinRMClientException- for any other failure
-
waitFor
public int waitFor()Wait for the command to complete, buffering any unread output in the meantime (read it afterward fromstdout()/stderr()).- Returns:
- the command's exit code
- Throws:
WinRMTimeoutException- when the command stays silent for a whole inactivity timeoutWinRMClientException- for any other failure
-
poll
Advance the stream by at most one bounded protocol round trip: ask the server to answer within the given wait — with output when it has any, with the protocol's "nothing yet" otherwise — buffer whatever arrives for the readers, and report whether the command has completed. An empty answer is not a failure: the process stays fully usable, so a polling consumer (e.g. an interactive session pump) never trips the inactivity timeout while idle. UnlikewaitFor(Duration), which keeps polling until its deadline, this returns as soon as the server answers: output that is ready arrives (and can be read) immediately.The wait is the polling cadence, not a hard bound on the round trip: how long the answer itself may take to arrive is governed by the request timeout (the inactivity timeout), so one slow answer from a loaded server does not fail the stream — use
waitFor(Duration)when a hard deadline is needed. The request timeout also caps the cadence, and a resulting budget too short for a network round trip — the WSMan service holds a bounded Receive for at least 500 ms before answering "nothing yet" — is waited out locally without touching the wire: the stream then does not advance. So poll with waits of about a second or more, on a request whose timeout is at least as long; a shorter request timeout leaveswaitFor()and the readers as the ways to advance.- Parameters:
maxWait- when the server should answer at the latest (at least one millisecond)- Returns:
truewhen the command has completed — the exit code is then available fromexitCode()—falsewhen it is still running- Throws:
WinRMTimeoutException- when the server stays silent for a whole inactivity timeoutWinRMClientException- for any other failure
-
waitFor
Wait at most the given duration for the command to complete — an overall deadline, on top of the per-response inactivity timeout. The remaining wait is a hard bound on the active protocol round trip: the server is asked to answer early enough for its reply to arrive within it, and a wait too short for any network round trip is waited out locally without touching the wire. Expiry does not affect the command: it keeps running, the process stays fully usable, and the caller decides whether to keep waiting orclose().- Parameters:
deadline- how long to wait (at least one millisecond)- Returns:
truewhen the command completed within the given duration — the exit code is then available fromexitCode()—falsewhen the wait expired first- Throws:
WinRMTimeoutException- when the server does not answer the bounded requests within the remaining wait — a peer that stopped answering cannot hold the wait past its deadlineWinRMClientException- for any other failure
-
exitCode
public int exitCode()Get the exit code of the completed command.- Returns:
- the exit code
- Throws:
IllegalStateException- when the command has not completed yet — wait for completion withwaitFor(), or read the output streams to their end first — or when the process was closed before the command completed
-
close
public void close()Terminate the command (when it is still running) and release the client's connection. Idempotent; a no-op when the command already completed. Output buffered before the close remains readable, then the readers report end of stream;waitFor()andexitCode()throwIllegalStateExceptionwhen the close preceded completion — a terminated command has no exit code.- Specified by:
closein interfaceAutoCloseable
-