record DynamicRoute(String from, String to) {} DynamicRoute readRoute(Message message, String controlMailbox) { var mailboxes = message.value().lines().toList(); if (mailboxes.size() != 2 || mailboxes.get(0).isBlank() || mailboxes.get(1).isBlank()) { IO.println("ROUTE needs exactly two lines: and "); return null; } var route = new DynamicRoute(mailboxes.get(0), mailboxes.get(1)); try { FileMessageBoard.directory(route.from()); FileMessageBoard.directory(route.to()); } catch (IllegalArgumentException exception) { IO.println("Rejected ROUTE: " + exception.getMessage()); return null; } if (route.from().equals(route.to())) { IO.println("Rejected ROUTE: from and to must differ"); return null; } if (route.from().equals(controlMailbox) || route.to().equals(controlMailbox)) { IO.println("Rejected ROUTE: the control mailbox is not a data mailbox"); return null; } return route; } void main(String[] arguments) throws Exception { if (arguments.length != 1 || !arguments[0].matches("[A-Za-z0-9_-]+")) { IO.println("Usage: java DynamicMediatorService.java "); return; } var name = arguments[0]; var controlMailbox = "mediators/" + name + "/inbox"; try (var subscriptions = new FileSubscriptions()) { DynamicRoute route = null; subscriptions.subscribe(controlMailbox); IO.println(name + " waits for ROUTE on " + controlMailbox); while (true) { var incoming = subscriptions.take(); var message = incoming.message(); if (incoming.mailbox().equals(controlMailbox)) { if (!message.type().equals("ROUTE")) { IO.println("Ignored " + message.type() + "; expected ROUTE"); continue; } var requestedRoute = readRoute(message, controlMailbox); if (requestedRoute == null) continue; if (route == null || !route.from().equals(requestedRoute.from())) { subscriptions.subscribe(requestedRoute.from()); if (route != null) subscriptions.unsubscribe(route.from()); } route = requestedRoute; IO.println( name + " now mediates: " + route.from() + " -> " + route.to() ); } else if (route != null && incoming.mailbox().equals(route.from())) { FileMessageBoard.publish(route.to(), message); } } } }