Refactor `TaskProcessorCommand` to use `TaskPriorityQueue` for improved task prioriti...
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 28 Dec 2025 18:27:19 +0000 (20:27 +0200)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sun, 28 Dec 2025 18:27:19 +0000 (20:27 +0200)
src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskPriorityQueue.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskProcessorCommand.java

diff --git a/src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskPriorityQueue.java b/src/main/java/eu/svjatoslav/alyverkko_cli/commands/task_processor/TaskPriorityQueue.java
new file mode 100644 (file)
index 0000000..23d12df
--- /dev/null
@@ -0,0 +1,62 @@
+package eu.svjatoslav.alyverkko_cli.commands.task_processor;
+
+import java.util.*;
+import java.util.function.Predicate;
+import eu.svjatoslav.alyverkko_cli.commands.task_processor.TaskProcessorCommand.TaskQueueEntry;
+
+
+/**
+ * A custom priority queue implementation for TaskQueueEntry that maintains tasks in priority order.
+ * Uses a TreeSet for efficient insertion, polling, and iteration.
+ */
+public class TaskPriorityQueue {
+    private final TreeSet<TaskQueueEntry> tasks;
+
+    /**
+     * Constructs a new empty task priority queue.
+     */
+    public TaskPriorityQueue() {
+        tasks = new TreeSet<>();
+    }
+
+    /**
+     * Adds a task to the priority queue.
+     *
+     * @param task the task to add (must not be null)
+     */
+    public void add(TaskQueueEntry task) {
+        tasks.add(task);
+    }
+
+    /**
+     * Removes and returns the highest priority task from the queue.
+     *
+     * @return the highest priority task, or null if the queue is empty
+     */
+    public TaskQueueEntry poll() {
+        if (tasks.isEmpty()) {
+            return null;
+        }
+        TaskQueueEntry task = tasks.first();
+        tasks.remove(task);
+        return task;
+    }
+
+    /**
+     * Removes tasks matching the given predicate.
+     *
+     * @param predicate the condition for removal (must not be null)
+     */
+    public void removeIf(Predicate<TaskQueueEntry> predicate) {
+        tasks.removeIf(predicate);
+    }
+
+    /**
+     * Returns all tasks in the queue in order of priority (highest priority first).
+     *
+     * @return a new list containing all tasks in priority order
+     */
+    public List<TaskQueueEntry> getAllTasks() {
+        return new ArrayList<>(tasks);
+    }
+}
index 07b96f4..596cb98 100644 (file)
@@ -37,6 +37,11 @@ import static java.nio.file.StandardWatchEventKinds.*;
  */
 public class TaskProcessorCommand implements Command {
 
+    /**
+     * A custom priority queue implementation that maintains tasks in priority order.
+     */
+    private final TaskPriorityQueue taskQueue = new TaskPriorityQueue();
+
     /**
      * A command-line parser to handle "mail" command arguments.
      */
@@ -65,12 +70,6 @@ public class TaskProcessorCommand implements Command {
      */
     File taskDirectory;
 
-    /**
-     * Priority queue of tasks to process, sorted by priority and a
-     * random tiebreaker.
-     */
-    private final PriorityQueue<TaskQueueEntry> taskQueue;
-
     public TaskProcessorCommand() {
         Comparator<TaskQueueEntry> comparator = (a, b) -> {
             int priorityCompare = Integer.compare(b.priority, a.priority);
@@ -79,7 +78,6 @@ public class TaskProcessorCommand implements Command {
             }
             return a.tiebreaker.compareTo(b.tiebreaker);
         };
-        this.taskQueue = new PriorityQueue<>(comparator);
     }
 
     /**
@@ -127,7 +125,8 @@ public class TaskProcessorCommand implements Command {
         // Main loop: process tasks from the queue in priority order
         while (true) {
             // Process the highest priority task if available
-            if (!taskQueue.isEmpty()) processTask(taskQueue.poll());
+            TaskQueueEntry nextTask = taskQueue.poll();
+            if (nextTask != null) processTask(nextTask);
 
             // Check for filesystem events
             WatchKey key = directoryWatcher.poll();
@@ -484,14 +483,14 @@ public class TaskProcessorCommand implements Command {
                 System.err.println("Invalid priority in file " + filePath.getFileName() + ": " + priorityStr);
             }
         }
-        taskQueue.offer(new TaskQueueEntry(filePath, priority));
+        taskQueue.add(new TaskQueueEntry(filePath, priority));
     }
 
     /**
      * A static nested class representing a task in the queue, with a
      * priority and a tiebreaker for sorting.
      */
-    private static class TaskQueueEntry implements Comparable<TaskQueueEntry> {
+    public static class TaskQueueEntry implements Comparable<TaskQueueEntry> {
         private final Path filePath;
         private final int priority;
         private final String tiebreaker;
@@ -526,26 +525,11 @@ public class TaskProcessorCommand implements Command {
 
     /**
      * Removes all tasks from the queue that match the given file path.
-     * This is done by draining the queue into a list, filtering out the matching entries,
-     * and re-adding the remaining ones back into the queue.
      *
      * @param filePath the file path to match and remove from the queue.
      */
     private void removeTasksForFile(Path filePath) {
-        List<TaskQueueEntry> remaining = new ArrayList<>();
-
-        // Drain all elements into a list
-        while (!taskQueue.isEmpty()) {
-            TaskQueueEntry entry = taskQueue.poll();
-            if (!entry.getFilePath().equals(filePath)) {
-                remaining.add(entry);
-            }
-        }
-
-        // Re-add all remaining entries back to the queue
-        for (TaskQueueEntry entry : remaining) {
-            taskQueue.offer(entry);
-        }
+        taskQueue.removeIf(entry -> entry.getFilePath().equals(filePath));
     }
 
 }