import java.io.IOException; import java.io.UncheckedIOException; import java.util.concurrent.LinkedBlockingQueue; record Route(String from, String to) {} Route waitForRoute(String controlMailbox) throws InterruptedException { var messages = new LinkedBlockingQueue(); var controlListener = Thread.ofVirtual().start(() -> { try { FileMessageBoard.watch(controlMailbox, messages::add); } catch (InterruptedException _) { Thread.currentThread().interrupt(); } catch (IOException exception) { throw new UncheckedIOException(exception); } }); try { while (true) { var message = messages.take(); if (!message.type().equals("ROUTE")) { IO.println("Ignored " + message.type() + "; expected ROUTE"); continue; } 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 "); continue; } return new Route(mailboxes.get(0), mailboxes.get(1)); } } finally { controlListener.interrupt(); controlListener.join(); } } void main(String[] arguments) throws Exception { if (arguments.length != 1 || !arguments[0].matches("[A-Za-z0-9_-]+")) { IO.println("Usage: java ConfigurableMediator.java "); return; } var name = arguments[0]; var controlMailbox = "mediators/" + name + "/inbox"; IO.println(name + " waits for ROUTE on " + controlMailbox); var route = waitForRoute(controlMailbox); IO.println(name + " mediates: " + route.from() + " -> " + route.to()); FileMessageBoard.watch(route.from(), message -> { try { FileMessageBoard.publish(route.to(), message); } catch (IOException exception) { throw new UncheckedIOException(exception); } }); }