diff --git a/commander/src/main/java/hse/java/commander/MainController.java b/commander/src/main/java/hse/java/commander/MainController.java index 5de3b66d..fa18335e 100644 --- a/commander/src/main/java/hse/java/commander/MainController.java +++ b/commander/src/main/java/hse/java/commander/MainController.java @@ -1,45 +1,133 @@ package hse.java.commander; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ListView; - -import java.nio.file.Path; +import javafx.scene.input.MouseEvent; public class MainController { - @FXML - public ListView left; + private enum FileOperation { + COPY, MOVE, DELETE + } - @FXML - public ListView right; + @FXML public ListView left; + @FXML public ListView right; - @FXML - public Button move; + @FXML public Button move; + @FXML public Button copy; + @FXML public Button delete; private Path leftDir; private Path rightDir; + private boolean isLeftActive = true; + // for testing public void setInitialDirs(Path leftStart, Path rightStart) { this.leftDir = leftStart; this.rightDir = rightStart; + refreshPanels(); + } + + private void updateList(Path dir, ListView dir_list) { + dir_list.getItems().clear(); + dir_list.getItems().add("..."); + + if (dir != null) { + try (java.nio.file.DirectoryStream dirStream = java.nio.file.Files.newDirectoryStream(dir)) { + for (Path path : dirStream) { + dir_list.getItems().add(path.getFileName().toString()); + } + } catch (java.io.IOException e) { + System.err.println(e.getMessage()); + } + } } public void initialize() { - move.setOnMouseClicked(event -> { + if (leftDir == null) leftDir = Path.of(System.getProperty("user.home")); + if (rightDir == null) rightDir = Path.of(System.getProperty("user.home")); + + refreshPanels(); + + left.setOnMouseClicked(event -> handlePanelClick(event, left, true)); + right.setOnMouseClicked(event -> handlePanelClick(event, right, false)); + + if (copy != null) copy.setOnAction(e -> executeOperation(FileOperation.COPY)); + if (move != null) move.setOnAction(e -> executeOperation(FileOperation.MOVE)); + if (delete != null) delete.setOnAction(e -> executeOperation(FileOperation.DELETE)); + } + + private void handlePanelClick(MouseEvent event, ListView list, boolean isLeft) { + isLeftActive = isLeft; + + if (isLeft) { + right.getSelectionModel().clearSelection(); + } else { + left.getSelectionModel().clearSelection(); + } - }); - System.out.println(System.getProperty("user.home")); - left.getItems().add("Kek"); + if (event.getClickCount() == 2) { + String selected = list.getSelectionModel().getSelectedItem(); + if (selected == null) return; - left.setOnMouseClicked(event -> { - if (event.getClickCount() == 2) { - int index = left.getSelectionModel().getSelectedIndex(); - if (index >= 0) { - left.getItems().set(index, "clicked"); + Path currentDir = isLeft ? leftDir : rightDir; + Path newDir; + + if (selected.equals("...")) { + newDir = currentDir.getParent(); + } else { + newDir = currentDir.resolve(selected); + } + + if (newDir != null && Files.isDirectory(newDir)) { + if (isLeft) leftDir = newDir; else rightDir = newDir; + refreshPanels(); + } + } + } + + private void executeOperation(FileOperation op) { + ListView activeList = isLeftActive ? left : right; + Path sourceDir = isLeftActive ? leftDir : rightDir; + Path targetDir = isLeftActive ? rightDir : leftDir; + + String selected = activeList.getSelectionModel().getSelectedItem(); + + if (selected == null || selected.equals("...")) return; + + Path sourcePath = sourceDir.resolve(selected); + + try { + switch (op) { + case COPY -> { + Path targetPath = targetDir.resolve(selected); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); + } + case MOVE -> { + Path targetPath = targetDir.resolve(selected); + Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); + } + case DELETE -> { + Files.delete(sourcePath); } } - }); + } catch (IOException e) { + System.err.println(e.getMessage()); + } + + refreshPanels(); + } + + private void refreshPanels() { + updateList(leftDir, left); + updateList(rightDir, right); } } + diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java index 816f3ee6..ff9cffd3 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/queue/BoundedBlockingQueue.java @@ -2,24 +2,77 @@ public class BoundedBlockingQueue { + private class Node { + T value; + Node next; + + Node(T value_) { + value = value_; + next = null; + } + } + + private final int capacity_; + private int size_; + private Node first = null; + private Node last = null; public BoundedBlockingQueue(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException(); + } + capacity_ = capacity; + } + public synchronized void put(T item) throws InterruptedException { + if (item == null) { + throw new NullPointerException(""); + } + Node node = new Node<>(item); + while (isFull()) { + this.wait(); + } + if (first == null) { + first = node; + last = node; + } else { + last.next = node; + last = node; + } + size_++; + this.notifyAll(); } - public void put(T item) throws InterruptedException { + public synchronized boolean isFull() { + return size_ == capacity_; + } + public synchronized boolean isEmpty() { + return size_ == 0; } - public T take() throws InterruptedException { - return null; + public synchronized T take() throws InterruptedException { + while (isEmpty()) { + this.wait(); + } + + T ret = first.value; + + first = first.next; + if (first == null) { + last = null; + } + size_--; + this.notifyAll(); + + return ret; } - public int size() { - return 0; + public synchronized int size() { + return size_; } - public int capacity() { - return 0; + public synchronized int capacity() { + return capacity_; } } diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java index fedb5e66..a4747d95 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamWriter.java @@ -1,9 +1,9 @@ package hse.java.lectures.lecture6.tasks.synchronizer; -import lombok.Getter; - import java.io.PrintStream; +import lombok.Getter; + public class StreamWriter implements Runnable { private final String message; @@ -26,11 +26,20 @@ public void attachMonitor(StreamingMonitor monitor) { @Override public void run() { - // Writer threads are intentionally infinite for the task contract. while (true) { - output.print(message); - onTick.run(); + try { + if (!monitor.waitMyTurn(id)) { + break; + } + + output.print(message); + onTick.run(); + + monitor.finishMyTurn(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } } } - -} +} \ No newline at end of file diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java index 68e8f279..50c8de19 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/StreamingMonitor.java @@ -1,5 +1,32 @@ package hse.java.lectures.lecture6.tasks.synchronizer; public class StreamingMonitor { - // impl your sync here -} + private final int[] orderedIds; + private final int maxTotalTicks; + private int currentTurnIndex = 0; + private int currentTotalTicks = 0; + + public StreamingMonitor(int[] orderedIds, int ticksPerWriter) { + this.orderedIds = orderedIds; + this.maxTotalTicks = orderedIds.length * ticksPerWriter; + } + + public synchronized boolean waitMyTurn(int id) throws InterruptedException { + while (currentTotalTicks < maxTotalTicks && orderedIds[currentTurnIndex] != id) { + wait(); + } + return currentTotalTicks < maxTotalTicks; + } + + public synchronized void finishMyTurn() { + currentTotalTicks++; + currentTurnIndex = (currentTurnIndex + 1) % orderedIds.length; + notifyAll(); + } + + public synchronized void awaitCompletion() throws InterruptedException { + while (currentTotalTicks < maxTotalTicks) { + wait(); + } + } +} \ No newline at end of file diff --git a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java index 3cb8aded..687f1860 100644 --- a/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java +++ b/src/main/java/hse/java/lectures/lecture6/tasks/synchronizer/Synchronizer.java @@ -17,17 +17,25 @@ public Synchronizer(List tasks, int ticksPerWriter) { this.ticksPerWriter = ticksPerWriter; } - /** - * Starts infinite writer threads and waits until each writer prints exactly ticksPerWriter ticks - * in strict ascending id order. - */ public void execute() { - // add monitor and sync + int[] orderedIds = tasks.stream() + .mapToInt(StreamWriter::getId) + .sorted() + .toArray(); + + StreamingMonitor monitor = new StreamingMonitor(orderedIds, ticksPerWriter); + for (StreamWriter writer : tasks) { + writer.attachMonitor(monitor); Thread worker = new Thread(writer, "stream-writer-" + writer.getId()); worker.setDaemon(true); worker.start(); } - } -} + try { + monitor.awaitCompletion(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} \ No newline at end of file