Skip to content
Closed

Lab3 #10

Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
target/
/.idea/
.env
Empty file modified mvnw
100644 → 100755
Empty file.
16 changes: 16 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>4.0.0-beta.15</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand Down
34 changes: 32 additions & 2 deletions src/main/java/com/example/HelloController.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
package com.example;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;

/**
* Controller layer: mediates between the view (FXML) and the model.
*/
public class HelloController {

private final HelloModel model = new HelloModel();
private final HelloModel model = new HelloModel(new NtfyConnectionImpl());

public ListView<NtfyMessageDto> messageView;

@FXML
private Label messageLabel;

@FXML
private TextField inputField;

@FXML
private TextField topicField;

@FXML
private void initialize() {
if (messageLabel != null) {
messageLabel.setText(model.getGreeting());
}

inputField.textProperty().bindBidirectional(model.messageToSendProperty());

topicField.textProperty().bindBidirectional(model.topicProperty());

messageView.setItems(model.getMessages());

model.connectToTopic();
}

public void sendMessage(ActionEvent actionEvent) {
if (!inputField.getText().trim().isEmpty()) {
model.sendMessage();
inputField.clear();
}
}

public void connectToTopic(ActionEvent actionEvent) {
model.connectToTopic();
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/example/HelloFX.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class HelloFX extends Application {
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml"));
Parent root = fxmlLoader.load();
Scene scene = new Scene(root, 640, 480);
stage.setTitle("Hello MVC");
Scene scene = new Scene(root, 740, 480);
stage.setTitle("JavaFX Chat App \uD83D\uDCAC");
stage.setScene(scene);
stage.show();
}
Expand Down
58 changes: 58 additions & 0 deletions src/main/java/com/example/HelloModel.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,54 @@
package com.example;

import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
* Model layer: encapsulates application data and business logic.
*/
public class HelloModel {

private final NtfyConnection connection;
private final ObservableList<NtfyMessageDto> messages = FXCollections.observableArrayList();
private final StringProperty messageToSend = new SimpleStringProperty();
private final StringProperty topic = new SimpleStringProperty("mytopic");

public HelloModel(NtfyConnection connection) {
this.connection = connection;
receiveMessage();
}

public ObservableList<NtfyMessageDto> getMessages() {
return messages;
}

public StringProperty messageToSendProperty() {
return messageToSend;
}

public String getMessageToSend() {
return messageToSend.get();
}

public void setMessageToSend(String message) {
messageToSend.set(message);
}

public String getTopic() {
return topic.get();
}

public StringProperty topicProperty() {
return topic;
}

public void setTopic(String topic) {
this.topic.set(topic);
}

/**
* Returns a greeting based on the current Java and JavaFX versions.
*/
Expand All @@ -12,4 +57,17 @@ public String getGreeting() {
String javafxVersion = System.getProperty("javafx.version");
return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".";
}

public void sendMessage() {
connection.send(topic.get(), messageToSend.get());
}

public void connectToTopic() {
messages.clear();
receiveMessage();
}

public void receiveMessage() {
connection.receive(topic.get(), m -> Platform.runLater(() -> messages.add(m)));
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/example/NtfyConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example;

import java.util.function.Consumer;

public interface NtfyConnection {

public boolean send(String topic, String message);

public void receive(String topic, Consumer<NtfyMessageDto> messageHandler);

}
74 changes: 74 additions & 0 deletions src/main/java/com/example/NtfyConnectionImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.example;

import io.github.cdimascio.dotenv.Dotenv;
import tools.jackson.databind.ObjectMapper;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix invalid Jackson import for ObjectMapper.

tools.jackson.databind.ObjectMapper does not exist, so this class will not compile. Switch to the correct Jackson package.

-import tools.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import tools.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
🤖 Prompt for AI Agents
In src/main/java/com/example/NtfyConnectionImpl.java around line 4, the import
uses the non-existent package tools.jackson.databind.ObjectMapper; replace it
with the correct Jackson import com.fasterxml.jackson.databind.ObjectMapper so
the class compiles and uses the proper ObjectMapper implementation from the
Jackson library.


import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

public class NtfyConnectionImpl implements NtfyConnection {

private final HttpClient http = HttpClient.newHttpClient();
private final String hostName;
private final ObjectMapper mapper = new ObjectMapper();
private CompletableFuture<Void> receiveTask;

public NtfyConnectionImpl() {
Dotenv dotenv = Dotenv.load();
hostName = Objects.requireNonNull(dotenv.get("HOST_NAME"));
}

public NtfyConnectionImpl(String hostName) {
this.hostName = hostName;
}

@Override
public boolean send(String topic, String message) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(message))
.header("Cache", "no")
.uri(URI.create(hostName + "/" + topic))
.build();
try {
var reponse = http.send(httpRequest, HttpResponse.BodyHandlers.discarding());
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
return true;
} catch (IOException e) {
System.out.println("Error sending message");
} catch (InterruptedException e) {
System.out.println("Interruped sending message");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Thread.currentThread().interrupt();
}
return false;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

@Override
public synchronized void receive(String topic, Consumer<NtfyMessageDto> messageHandler) {
if (receiveTask != null) {
receiveTask.cancel(true);
}
HttpRequest httpRequest = HttpRequest.newBuilder()
.GET()
.uri(URI.create(hostName + "/" + topic + "/json"))
.build();

receiveTask = http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
.thenAccept(response -> response.body()
.map(s -> {
try {
return mapper.readValue(s, NtfyMessageDto.class);
} catch (Exception e) {
return null;
}
})
.filter(Objects::nonNull)
.filter(message -> "message".equals(message.event()))
.peek(System.out::println)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.forEach(messageHandler));
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/example/NtfyMessageDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public record NtfyMessageDto(String id, long time, String event, String topic, String message) {

@Override
public String toString() {
return message;
}

}
3 changes: 3 additions & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module hellofx {
requires javafx.controls;
requires javafx.fxml;
requires io.github.cdimascio.dotenv.java;
requires java.net.http;
requires tools.jackson.databind;

opens com.example to javafx.fxml;
exports com.example;
Expand Down
48 changes: 40 additions & 8 deletions src/main/resources/com/example/hello-view.fxml
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.Label?>

<StackPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.HelloController">
<children>
<Label fx:id="messageLabel" text="Hello, JavaFX!" />
</children>
</StackPane>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="CENTER" spacing="15"
xmlns="http://javafx.com/javafx/17.0.12"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.example.HelloController">

<padding>
<Insets bottom="20" left="20" right="20" top="20" />
</padding>

<Label fx:id="messageLabel"
style="-fx-font-size: 20px;"
text="JavaFX Chat App 💬" />

<HBox alignment="CENTER_LEFT"
spacing="10">
<Label text="Topic:" />
<TextField fx:id="topicField"
text="mytopic"
HBox.hgrow="ALWAYS" />
<Button text="Connect"
onAction="#connectToTopic" />
</HBox>

<HBox spacing="10">
<TextField fx:id="inputField"
promptText="Type a message!"
HBox.hgrow="ALWAYS" />
<Button text="Send"
onAction="#sendMessage" />
</HBox>

<ListView fx:id="messageView"
VBox.vgrow="ALWAYS" />

</VBox>
Loading
Loading