Skip to content

Commit dd74613

Browse files
committed
CommonRails: add process registry and on-exit listeners; register TelnetInstaller process for monitoring\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bd210f3 commit dd74613

2 files changed

Lines changed: 73 additions & 0 deletions

File tree

source/commons/CommonRails.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import java.text.SimpleDateFormat;
77
import java.util.ArrayList;
88
import java.util.Date;
9+
import java.util.List;
10+
import java.util.Collections;
911

1012
public class CommonRails
1113
{
@@ -124,6 +126,70 @@ public static Boolean isSocketClosed(Socket socket)
124126
}
125127
}
126128

129+
// Registry for started Processes so CommonRails can monitor them and print on exit
130+
protected static final List<Process> REGISTERED_PROCESSES = Collections.synchronizedList(new ArrayList<Process>());
131+
132+
/**
133+
* Register a started Process with CommonRails. CommonRails will attach a listener
134+
* to the process' onExit CompletableFuture (Java 9+) and print when the process exits.
135+
* If onExit is unavailable/throws, a watcher thread using waitFor is started as a fallback.
136+
*/
137+
public static synchronized void registerProcess(ProcessBuilder pb, Process process, Object owner)
138+
{
139+
if (process == null) return;
140+
141+
REGISTERED_PROCESSES.add(process);
142+
143+
Object printer = (owner == null) ? CommonRails.class : owner;
144+
145+
try
146+
{
147+
CommonRails.printSystemComponent(printer, process.hashCode(), ". CommonRails::registerProcess >> registered process: " + process);
148+
149+
// Attach onExit listener
150+
process.onExit().thenAccept(p -> {
151+
try
152+
{
153+
CommonRails.printSystemComponent(printer, p.hashCode(), ". CommonRails::processExited >> process closed: " + p + " exit=" + p.exitValue());
154+
}
155+
catch (Throwable t)
156+
{
157+
// Best-effort printing
158+
CommonRails.printSystemComponent(printer, p.hashCode(), ". CommonRails::processExited >> process closed: " + p);
159+
}
160+
finally
161+
{
162+
REGISTERED_PROCESSES.remove(p);
163+
}
164+
});
165+
}
166+
catch (Throwable t)
167+
{
168+
// Fallback: spawn a watcher thread that waits for the process
169+
new Thread(() -> {
170+
try
171+
{
172+
int rv = process.waitFor();
173+
174+
CommonRails.printSystemComponent(printer, process.hashCode(), ". CommonRails::processExited(watcher) >> process closed: " + process + " exit=" + rv);
175+
}
176+
catch (Exception e)
177+
{
178+
e.printStackTrace(System.err);
179+
}
180+
finally
181+
{
182+
REGISTERED_PROCESSES.remove(process);
183+
}
184+
}, "CommonRails-ProcessWatcher-" + process.hashCode()).start();
185+
}
186+
}
187+
188+
public static synchronized List<Process> getRegisteredProcesses()
189+
{
190+
return new ArrayList<>(REGISTERED_PROCESSES);
191+
}
192+
127193
public static class TelnetCallOnComplete implements Runnable
128194
{
129195
protected WebExpress web_express;

source/telnet/TelnetInstaller.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ public TelnetInstaller(WebExpress web_express)
3535

3636
this.process = process_builder.start();
3737

38+
// register process with CommonRails so it can monitor exit/finish events
39+
try {
40+
CommonRails.registerProcess(this.process_builder, this.process, this);
41+
} catch (Exception ignore) {
42+
// best-effort: don't let registration prevent initialization
43+
}
44+
3845
this.reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
3946

4047
this.writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

0 commit comments

Comments
 (0)