11package org.bread_experts_group.application_carpool.supervisor
22
33import org.bread_experts_group.application_carpool.rmi.Supervisor
4+ import org.bread_experts_group.command_line.Flag
5+ import org.bread_experts_group.command_line.readArgs
6+ import org.bread_experts_group.command_line.stringToInt
47import rmi.ApplicationInfo
58import rmi.ApplicationNotFoundException
9+ import java.nio.file.Path
10+ import java.rmi.registry.LocateRegistry
611import java.rmi.server.UnicastRemoteObject
12+ import java.util.logging.FileHandler
13+ import java.util.logging.Level
714import java.util.logging.Logger
15+ import java.util.logging.SimpleFormatter
16+ import kotlin.io.path.Path
817import kotlin.system.exitProcess
918
10- class CarpoolSupervisor (val pid : Long , val logger : Logger ) : UnicastRemoteObject(0 ), Supervisor {
19+ private val FLAGS = listOf (
20+ Flag (
21+ " log_level" ,
22+ " Log level" ,
23+ default = Level .INFO ,
24+ conv = Level ::parse
25+ ),
26+ Flag (
27+ " port" ,
28+ " Port" ,
29+ default = 1099 ,
30+ conv = stringToInt()
31+ ),
32+ Flag (
33+ " log_dir" ,
34+ " Log directory" ,
35+ default = Path (" ./logs/" ),
36+ conv = { Path (it) }
37+ )
38+ )
39+ private val LOGGER = Logger .getLogger(" Application Carpool Supervisor" )
40+
41+ class CarpoolSupervisor (val pid : Long ) : UnicastRemoteObject(0 ), Supervisor {
1142 val applications = mutableMapOf<Long , ApplicationEntry >()
1243
1344 override fun status () = pid
1445
1546 override fun stop () {
16- logger .info(" Stop request received, shutting down applications" )
47+ LOGGER .info(" Stop request received, shutting down applications" )
1748 for (app in applications.values) app.handle.destroy()
18- logger .info(" Applications shut down, exiting supervisor daemon" )
49+ LOGGER .info(" Applications shut down, exiting supervisor daemon" )
1950 exitProcess(0 )
2051 }
2152
@@ -27,7 +58,7 @@ class CarpoolSupervisor(val pid: Long, val logger: Logger) : UnicastRemoteObject
2758
2859 override fun addApplication (commandArray : Array <String >): Long {
2960 val commandString = commandArray.joinToString(" " )
30- logger .info { " Starting application $commandString " }
61+ LOGGER .info { " Starting application $commandString " }
3162
3263 val app = Runtime .getRuntime().exec(commandArray)
3364 applications[app.pid()] = ApplicationEntry (app, commandString)
@@ -36,14 +67,63 @@ class CarpoolSupervisor(val pid: Long, val logger: Logger) : UnicastRemoteObject
3667
3768 override fun removeApplication (pid : Long ) {
3869 if (! applications.containsKey(pid)) {
39- logger .warning { " Could not find application with PID $pid " }
70+ LOGGER .warning { " Could not find application with PID $pid " }
4071 throw ApplicationNotFoundException (pid)
4172 }
4273
4374 val app = applications[pid]!!
4475 app.handle.destroy()
4576 applications.remove(pid)
46- logger.info { " Removed application with PID $pid (${app.commandString} )" }
77+ LOGGER .info { " Removed application with PID $pid (${app.commandString} )" }
78+ }
79+
80+ companion object {
81+ @JvmStatic
82+ fun main (args : Array <String >) {
83+ val args = readArgs(
84+ args,
85+ FLAGS ,
86+ " Application Carpool Supervisor" ,
87+ " Application Carpool Supervisor process"
88+ )
89+ val pid = ProcessHandle .current().pid()
90+ val port = args.getRequired<Int >(" port" )
91+
92+ val logFileHandler = FileHandler (
93+ args.getRequired<Path >(" log_dir" ).resolve(" supervisor-log.txt" ).toString(),
94+ )
95+ logFileHandler.formatter = SimpleFormatter ()
96+
97+ LOGGER .useParentHandlers = false
98+ LOGGER .addHandler(logFileHandler)
99+ LOGGER .level = args.getRequired<Level >(" log_level" )
100+ LOGGER .info { " Starting supervisor daemon -- PID $pid " }
101+
102+ var registry = LocateRegistry .getRegistry(port)
103+ val supervisorStub = CarpoolSupervisor (pid)
104+
105+ try {
106+ registry.bind(" CarpoolSupervisor" , supervisorStub)
107+ LOGGER .fine(" Connected to the local RMI registry" )
108+ } catch (e: Exception ) {
109+ try {
110+ LOGGER .log(Level .FINE , e) {
111+ " Could not connect to the local RMI registry on port $port , attempting to create our own"
112+ }
113+ registry = LocateRegistry .createRegistry(port)
114+ registry.bind(" CarpoolSupervisor" , supervisorStub)
115+ LOGGER .fine { " Connected to the self-made RMI registry on port $port " }
116+ } catch (e: Exception ) {
117+ LOGGER .log(Level .SEVERE , e) {
118+ " Could not connect to an RMI registry. If you have your own local registry, " +
119+ " please ensure you run it with -J-Djava.rmi.server.codebase=file:<YOUR CLASSPATH>/"
120+ }
121+ exitProcess(1 )
122+ }
123+ }
124+
125+ LOGGER .info(" Supervisor daemon started" )
126+ }
47127 }
48128
49129 data class ApplicationEntry (val handle : Process , val commandString : String )
0 commit comments