record Message(String type, String value) {} Map> mailboxes = new ConcurrentHashMap<>(); BlockingQueue mailbox(String name) { return mailboxes.computeIfAbsent( name, _ -> new LinkedBlockingQueue<>() ); } String rot13(String text) { var result = new StringBuilder(); for (var character : text.toCharArray()) { if (character >= 'a' && character <= 'z') character = (char) ('a' + (character - 'a' + 13) % 26); else if (character >= 'A' && character <= 'Z') character = (char) ('A' + (character - 'A' + 13) % 26); result.append(character); } return result.toString(); } void mediate(String from, String to) { try { while (true) mailbox(to).put(mailbox(from).take()); } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } void runConsoleIn() { try { while (true) { var text = IO.readln(); if (text == null) return; mailbox("consoleIn.outbox") .put(new Message("TEXT", text)); } } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } void runRot13() { try { while (true) { var input = mailbox("rot13.inbox").take(); var output = new Message("TEXT", rot13(input.value())); mailbox("rot13.outbox").put(output); } } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } void runConsoleOut() { try { while (true) IO.println(mailbox("consoleOut.inbox").take().value()); } catch (InterruptedException _) { Thread.currentThread().interrupt(); } } void main() throws InterruptedException { Thread.ofVirtual().start(this::runConsoleIn); Thread.ofVirtual().start(this::runRot13); Thread.ofVirtual().start(this::runConsoleOut); Thread.ofVirtual().start( () -> mediate("consoleIn.outbox", "rot13.inbox") ); Thread.ofVirtual().start( () -> mediate("rot13.outbox", "consoleOut.inbox") ); Thread.currentThread().join(); }