summaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/it_jaros/jscanner/PollState.java13
-rw-r--r--src/main/java/com/it_jaros/jscanner/Scanner.java45
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;
}
}