diff options
| author | 2026-08-02 19:07:52 +0200 | |
|---|---|---|
| committer | 2026-08-02 19:13:16 +0200 | |
| commit | ed329553e5ccd26c481582fae654f1674fd083a3 (patch) | |
| tree | 5901162c9e9450a437382673e7084ab585341faf /src | |
| parent | b827ce8853202664091f9fcc53b75d4a361d6a8b (diff) | |
Added PollState to have a wrapper instead of returning null
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/java/com/it_jaros/jscanner/PollState.java | 13 | ||||
| -rw-r--r-- | src/main/java/com/it_jaros/jscanner/Scanner.java | 45 |
2 files changed, 34 insertions, 24 deletions
diff --git a/src/main/java/com/it_jaros/jscanner/PollState.java b/src/main/java/com/it_jaros/jscanner/PollState.java new file mode 100644 index 0000000..474c055 --- /dev/null +++ b/src/main/java/com/it_jaros/jscanner/PollState.java @@ -0,0 +1,13 @@ +package com.it_jaros.jscanner; + +/** + * A sealed interface representing the three possible outcomes of a CompletionService + * poll operation: successful result, task failure, or not ready yet. + * Makes error handling explicit — Failure and Unavailable are distinct and compile-time + * required to handle via exhaustiveness checking in switch statements. + */ +public sealed interface PollState<T> { + record Success<T>(T value) implements PollState<T> {} + record Failure<T>(Throwable error) implements PollState<T> {} + record Unavailable<T>() implements PollState<T> {} +} diff --git a/src/main/java/com/it_jaros/jscanner/Scanner.java b/src/main/java/com/it_jaros/jscanner/Scanner.java index e3c886b..fd6c0e5 100644 --- a/src/main/java/com/it_jaros/jscanner/Scanner.java +++ b/src/main/java/com/it_jaros/jscanner/Scanner.java @@ -77,11 +77,12 @@ public class Scanner implements AutoCloseable { // with whatever is there already while (state.running().get() || state.inPipeline().get() > 0) { try { - ScanResult result = getHostResult(state); - if (result == null) { - continue; + PollState<ScanResult> poll = getHostResult(state); + if (poll instanceof PollState.Success<ScanResult>(ScanResult value)) { + consumer.accept(value); + } else if (poll instanceof PollState.Failure<ScanResult>(Throwable error)) { + System.err.printf("Host task failed: %s%n", error.getMessage()); } - consumer.accept(result); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } @@ -90,25 +91,21 @@ public class Scanner implements AutoCloseable { scan.stop(); } - private ScanResult getHostResult(ProducerState<ScanResult> state) throws InterruptedException { - // let's check for results and give add them to our scan data holder object + private PollState<ScanResult> getHostResult(ProducerState<ScanResult> state) throws InterruptedException { Future<ScanResult> finishedHost = state.completionService().poll(10, TimeUnit.MILLISECONDS); if (finishedHost == null) { - return null; + return new PollState.Unavailable<>(); } - ScanResult result = null; try { - result = finishedHost.get(); + ScanResult result = finishedHost.get(); + return new PollState.Success<>(result); } catch (ExecutionException e) { - System.err.printf("%s -> %s%n", e.getClass().getSimpleName(), e.getMessage()); + return new PollState.Failure<>(e.getCause()); } finally { - // No matter what happens we have to free the resources after getting ScanResult state.activeWorkers().release(); state.inPipeline().decrementAndGet(); } - - return result; } /** @@ -251,12 +248,12 @@ public class Scanner implements AutoCloseable { final PortResultAccumulator accumulator = new PortResultAccumulator(host); while (!cancelled && (state.running().get() || state.inPipeline().get() > 0)) { try { - PortResult portResult = getPortResult(state); - if (portResult == null) { - continue; + PollState<PortResult> poll = getPortResult(state); + if (poll instanceof PollState.Success<PortResult>(PortResult value)) { + accumulator.add(value); + } else if (poll instanceof PollState.Failure(Throwable error)) { + System.err.printf("Port task failed: %s -> %s%n", error.getClass().getSimpleName(), error.getMessage()); } - - accumulator.add(portResult); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } @@ -275,23 +272,23 @@ public class Scanner implements AutoCloseable { return false; } - private PortResult getPortResult(ProducerState<PortResult> state) throws InterruptedException { + private PollState<PortResult> getPortResult(ProducerState<PortResult> state) throws InterruptedException { Future<PortResult> portResultFuture = state.completionService().poll(10, TimeUnit.MILLISECONDS); if (portResultFuture == null) { - return null; + return new PollState.Unavailable<>(); } - PortResult portResult = null; + PortResult portResult; try { portResult = portResultFuture.get(); + return new PollState.Success<>(portResult); } catch (ExecutionException e) { - // something more serious did not work - System.err.printf("%s -> %s%n", e.getClass().getSimpleName(), e.getMessage()); + Throwable cause = e.getCause(); + return new PollState.Failure<>(cause); } finally { state.activeWorkers().release(); state.inPipeline().decrementAndGet(); } - return portResult; } } |
