From 001f6444fec8fcd5312028cfdae90f4f93424559 Mon Sep 17 00:00:00 2001 From: Kostya Date: Fri, 14 Aug 2026 20:32:49 +0000 Subject: Collapse console I/O interfaces into InputProcessor, drop unneeded atomics InputProvider/OutputProvider each had one implementation and no test exercised the seam, so fold Console{Input,Output}Provider straight into InputProcessor and update Menu/MenuCommand call sites accordingly. Account and Event both use AtomicInteger for a ledger/trade id counter that's only ever touched next to a plain, non-thread-safe ArrayList add in the same method - the atomic bought no real thread-safety. Swapped both to plain int with ++. --- .../java/market/guess/service/domain/Account.java | 6 ++-- .../java/market/guess/service/domain/Event.java | 5 ++- .../java/market/guess/service/domain/Trade.java | 2 +- .../src/main/java/market/guess/ui/console/App.java | 6 ---- .../main/java/market/guess/ui/console/Menu.java | 19 +++++----- .../guess/ui/console/command/ExitMenuCommand.java | 10 +++--- .../ui/console/command/ListEventsMenuCommand.java | 20 +++++------ .../ui/console/command/LoadFileMenuCommand.java | 17 ++++----- .../guess/ui/console/io/ConsoleInputProvider.java | 17 --------- .../guess/ui/console/io/ConsoleOutputProvider.java | 24 ------------- .../market/guess/ui/console/io/InputProcessor.java | 41 +++++++++++++++------- .../market/guess/ui/console/io/InputProvider.java | 5 --- .../market/guess/ui/console/io/OutputProvider.java | 11 ------ 13 files changed, 63 insertions(+), 120 deletions(-) delete mode 100644 ui-console/src/main/java/market/guess/ui/console/io/ConsoleInputProvider.java delete mode 100644 ui-console/src/main/java/market/guess/ui/console/io/ConsoleOutputProvider.java delete mode 100644 ui-console/src/main/java/market/guess/ui/console/io/InputProvider.java delete mode 100644 ui-console/src/main/java/market/guess/ui/console/io/OutputProvider.java diff --git a/service/src/main/java/market/guess/service/domain/Account.java b/service/src/main/java/market/guess/service/domain/Account.java index 7e24cdb..d1a1841 100644 --- a/service/src/main/java/market/guess/service/domain/Account.java +++ b/service/src/main/java/market/guess/service/domain/Account.java @@ -4,7 +4,6 @@ import java.math.BigDecimal; import java.time.Clock; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import market.guess.api.LedgerType; public final class Account { @@ -12,7 +11,7 @@ public final class Account { private final Clock clock; private final List entries = new ArrayList<>(); private BigDecimal balance; - private AtomicInteger runningId = new AtomicInteger(); + private int runningId; public Account(String owner, BigDecimal initialBalance) { this(owner, initialBalance, Clock.systemUTC()); @@ -44,7 +43,6 @@ public final class Account { } private void record(LedgerType type, BigDecimal amount, String note) { - entries.add( - new LedgerEntry(runningId.incrementAndGet(), clock.instant(), type, amount, balance, note)); + entries.add(new LedgerEntry(++runningId, clock.instant(), type, amount, balance, note)); } } diff --git a/service/src/main/java/market/guess/service/domain/Event.java b/service/src/main/java/market/guess/service/domain/Event.java index cef0840..8f7e11d 100644 --- a/service/src/main/java/market/guess/service/domain/Event.java +++ b/service/src/main/java/market/guess/service/domain/Event.java @@ -4,7 +4,6 @@ import java.math.BigDecimal; import java.time.Instant; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import market.guess.api.CommissionTiming; import market.guess.api.EventStatus; import market.guess.api.EventSummaryDTO; @@ -22,7 +21,7 @@ public final class Event { private final Account account; private final String marketMaker; - private final AtomicInteger runningId = new AtomicInteger(); + private int runningId; private final List trades = new ArrayList<>(); private EventStatus status; private String winningOptionKey; @@ -125,7 +124,7 @@ public final class Event { BigDecimal commission) { var trade = new Trade( - runningId.incrementAndGet(), + ++runningId, time, user, option.getKey(), diff --git a/service/src/main/java/market/guess/service/domain/Trade.java b/service/src/main/java/market/guess/service/domain/Trade.java index 0c07749..1211280 100644 --- a/service/src/main/java/market/guess/service/domain/Trade.java +++ b/service/src/main/java/market/guess/service/domain/Trade.java @@ -9,7 +9,7 @@ public record Trade( String userName, String optionKey, String optionName, - int uantity, + int quantity, BigDecimal sharesCost, BigDecimal commission) { diff --git a/ui-console/src/main/java/market/guess/ui/console/App.java b/ui-console/src/main/java/market/guess/ui/console/App.java index 34638ac..3d42e9b 100644 --- a/ui-console/src/main/java/market/guess/ui/console/App.java +++ b/ui-console/src/main/java/market/guess/ui/console/App.java @@ -14,11 +14,7 @@ import market.guess.service.repository.UserRepository; import market.guess.ui.console.command.ExitMenuCommand; import market.guess.ui.console.command.ListEventsMenuCommand; import market.guess.ui.console.command.LoadFileMenuCommand; -import market.guess.ui.console.io.ConsoleInputProvider; -import market.guess.ui.console.io.ConsoleOutputProvider; import market.guess.ui.console.io.InputProcessor; -import market.guess.ui.console.io.InputProvider; -import market.guess.ui.console.io.OutputProvider; import org.picocontainer.DefaultPicoContainer; import org.picocontainer.behaviors.Caching; @@ -38,8 +34,6 @@ public class App { pico.addComponent(ListEventsMenuCommand.class); pico.addComponent(ExitMenuCommand.class); - pico.addComponent(InputProvider.class, ConsoleInputProvider.class); - pico.addComponent(OutputProvider.class, ConsoleOutputProvider.class); pico.addComponent(InputProcessor.class); pico.addComponent(Menu.class); diff --git a/ui-console/src/main/java/market/guess/ui/console/Menu.java b/ui-console/src/main/java/market/guess/ui/console/Menu.java index c1762dc..18b72b7 100644 --- a/ui-console/src/main/java/market/guess/ui/console/Menu.java +++ b/ui-console/src/main/java/market/guess/ui/console/Menu.java @@ -3,32 +3,29 @@ package market.guess.ui.console; import java.util.List; import market.guess.ui.console.command.MenuCommand; import market.guess.ui.console.io.InputProcessor; -import market.guess.ui.console.io.OutputProvider; import org.picocontainer.Startable; public final class Menu implements Startable { - private final OutputProvider out; - private final InputProcessor in; + private final InputProcessor io; private final List commands; - public Menu(List commands, OutputProvider out, InputProcessor in) { + public Menu(List commands, InputProcessor io) { this.commands = commands; - this.out = out; - this.in = in; + this.io = io; } @Override public void start() { var max = commands.stream().mapToInt(MenuCommand::getIndex).max().orElse(0); - out.splashScreen(); + io.splashScreen(); while (true) { printMenu(); - var selection = in.readInt("Choose a command: ", 1, max); + var selection = io.readInt("Choose a command: ", 1, max); var commandOptional = commands.stream().filter(c -> c.getIndex() == selection).findFirst(); if (commandOptional.isEmpty()) { - out.println("There is no command %d.".formatted(selection)); + io.println("There is no command %d.".formatted(selection)); continue; } var command = commandOptional.get(); @@ -45,9 +42,9 @@ public final class Menu implements Startable { } private void printMenu() { - out.newLine(); + io.newLine(); for (var command : commands) { - out.println(" [%d]->> %s".formatted(command.getIndex(), command.getName())); + io.println(" [%d]->> %s".formatted(command.getIndex(), command.getName())); } } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java index 372c686..23ed9c9 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/ExitMenuCommand.java @@ -1,13 +1,13 @@ package market.guess.ui.console.command; -import market.guess.ui.console.io.OutputProvider; +import market.guess.ui.console.io.InputProcessor; public final class ExitMenuCommand implements MenuCommand { - private final OutputProvider out; + private final InputProcessor io; - public ExitMenuCommand(OutputProvider out) { + public ExitMenuCommand(InputProcessor io) { super(); - this.out = out; + this.io = io; } @Override @@ -32,6 +32,6 @@ public final class ExitMenuCommand implements MenuCommand { @Override public void execute() { - out.println("Goodbye."); + io.println("Goodbye."); } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java index 6e6ace9..bad621d 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/ListEventsMenuCommand.java @@ -2,16 +2,16 @@ package market.guess.ui.console.command; import market.guess.api.CommissionTiming; import market.guess.api.GuessMarketContext; -import market.guess.ui.console.io.OutputProvider; +import market.guess.ui.console.io.InputProcessor; public final class ListEventsMenuCommand implements MenuCommand { private final GuessMarketContext context; - private final OutputProvider out; + private final InputProcessor io; - public ListEventsMenuCommand(GuessMarketContext context, OutputProvider out) { + public ListEventsMenuCommand(GuessMarketContext context, InputProcessor io) { super(); this.context = context; - this.out = out; + this.io = io; } @Override @@ -34,14 +34,14 @@ public final class ListEventsMenuCommand implements MenuCommand { var events = context.listEvents(); for (var event : events) { - out.newLine(); - out.println(" %s".formatted(event.name())); - out.println(" %s".formatted(event.description())); - out.println( + io.newLine(); + io.println(" %s".formatted(event.name())); + io.println(" %s".formatted(event.description())); + io.println( " Commission: %d%% (%s)" .formatted(event.commissionPercent(), timing(event.commissionTiming()))); - out.println(" Options: " + String.join(" | ", event.optionNames())); - out.println(" Status: " + event.status()); + io.println(" Options: " + String.join(" | ", event.optionNames())); + io.println(" Status: " + event.status()); } } diff --git a/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java b/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java index 4a56483..7005632 100644 --- a/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java +++ b/ui-console/src/main/java/market/guess/ui/console/command/LoadFileMenuCommand.java @@ -3,17 +3,14 @@ package market.guess.ui.console.command; import java.nio.file.Path; import market.guess.api.GuessMarketContext; import market.guess.ui.console.io.InputProcessor; -import market.guess.ui.console.io.OutputProvider; public final class LoadFileMenuCommand implements MenuCommand { private final GuessMarketContext context; - private final OutputProvider out; - private final InputProcessor in; + private final InputProcessor io; - public LoadFileMenuCommand(GuessMarketContext context, InputProcessor in, OutputProvider out) { + public LoadFileMenuCommand(GuessMarketContext context, InputProcessor io) { this.context = context; - this.out = out; - this.in = in; + this.io = io; } @Override @@ -33,18 +30,18 @@ public final class LoadFileMenuCommand implements MenuCommand { @Override public void execute() { - var path = in.readPath("Pleae enter the full file path to the XML file: "); + var path = io.readPath("Pleae enter the full file path to the XML file: "); var result = context.loadEvents(Path.of(path)); if (result.success()) { - out.println("Loaded %d event(s) from %s.".formatted(result.eventsLoaded(), result.source())); + io.println("Loaded %d event(s) from %s.".formatted(result.eventsLoaded(), result.source())); return; } - out.println( + io.println( "The file was not loaded. %d problem(s) were found: ".formatted(result.issues().size())); for (var issue : result.issues()) { - out.println(" - %s: %s".formatted(issue.location(), issue.humanizedMessage())); + io.println(" - %s: %s".formatted(issue.location(), issue.humanizedMessage())); } } } diff --git a/ui-console/src/main/java/market/guess/ui/console/io/ConsoleInputProvider.java b/ui-console/src/main/java/market/guess/ui/console/io/ConsoleInputProvider.java deleted file mode 100644 index 5c93f71..0000000 --- a/ui-console/src/main/java/market/guess/ui/console/io/ConsoleInputProvider.java +++ /dev/null @@ -1,17 +0,0 @@ -package market.guess.ui.console.io; - -import java.util.Scanner; - -public class ConsoleInputProvider implements InputProvider { - private final Scanner scanner = new Scanner(System.in); - - @Override - public void close() throws Exception { - scanner.close(); - } - - @Override - public String nextLine() { - return scanner.hasNextLine() ? scanner.nextLine() : null; - } -} diff --git a/ui-console/src/main/java/market/guess/ui/console/io/ConsoleOutputProvider.java b/ui-console/src/main/java/market/guess/ui/console/io/ConsoleOutputProvider.java deleted file mode 100644 index 6fa7595..0000000 --- a/ui-console/src/main/java/market/guess/ui/console/io/ConsoleOutputProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -package market.guess.ui.console.io; - -public class ConsoleOutputProvider implements OutputProvider { - - @Override - public void print(Object object) { - IO.print(object); - } - - @Override - public void println(Object object) { - IO.println(object); - } - - @Override - public void newLine() { - IO.println(""); - } - - @Override - public void splashScreen() { - IO.println("<<-- GUESS MARKET -->>"); - } -} diff --git a/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java b/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java index 9f03acb..4889c36 100644 --- a/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java +++ b/ui-console/src/main/java/market/guess/ui/console/io/InputProcessor.java @@ -1,41 +1,52 @@ package market.guess.ui.console.io; +import java.util.Scanner; + public final class InputProcessor { - private final OutputProvider out; - private final InputProvider in; + private final Scanner scanner = new Scanner(System.in); + + public void print(Object object) { + IO.print(object); + } + + public void println(Object object) { + IO.println(object); + } - public InputProcessor(InputProvider in, OutputProvider out) { - super(); - this.in = in; - this.out = out; + public void newLine() { + IO.println(""); + } + + public void splashScreen() { + IO.println("<<-- GUESS MARKET -->>"); } public String readLine(String prompt) { - out.print(prompt); - var line = in.nextLine(); + print(prompt); + var line = nextLine(); return line.trim(); } public int readInt(String prompt, int min, int max) { while (true) { - var raw = in.nextLine(); + var raw = nextLine(); if (raw.isBlank()) { - out.println("Please enter a number between %d and %d.".formatted(min, max)); + println("Please enter a number between %d and %d.".formatted(min, max)); continue; } try { var value = Integer.parseInt(raw); if (value > max || value < min) { - out.println( + println( "%d is out of range, please enter a number between %d and %d." .formatted(value, min, max)); continue; } return value; } catch (NumberFormatException e) { - out.println( + println( "%s in not a number, please enter a number between %d and %d." .formatted(raw, min, max)); continue; @@ -48,11 +59,15 @@ public final class InputProcessor { var raw = readLine(prompt); if (raw.isBlank()) { - out.println("Please enter a file path."); + println("Please enter a file path."); continue; } return raw; } } + + private String nextLine() { + return scanner.hasNextLine() ? scanner.nextLine() : null; + } } diff --git a/ui-console/src/main/java/market/guess/ui/console/io/InputProvider.java b/ui-console/src/main/java/market/guess/ui/console/io/InputProvider.java deleted file mode 100644 index 9404bb7..0000000 --- a/ui-console/src/main/java/market/guess/ui/console/io/InputProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package market.guess.ui.console.io; - -public interface InputProvider extends AutoCloseable { - String nextLine(); -} diff --git a/ui-console/src/main/java/market/guess/ui/console/io/OutputProvider.java b/ui-console/src/main/java/market/guess/ui/console/io/OutputProvider.java deleted file mode 100644 index e419351..0000000 --- a/ui-console/src/main/java/market/guess/ui/console/io/OutputProvider.java +++ /dev/null @@ -1,11 +0,0 @@ -package market.guess.ui.console.io; - -public interface OutputProvider { - void print(Object object); - - void newLine(); - - void splashScreen(); - - void println(Object object); -} -- cgit v1.2.3