Skip to content
Closed

Lab3 #31

Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@
<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>
</dependencies>
<build>
<plugins>
Expand Down
74 changes: 71 additions & 3 deletions src/main/java/com/example/HelloController.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.example;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.control.*;

/**
* Controller layer: mediates between the view (FXML) and the model.
Expand All @@ -10,13 +13,78 @@ public class HelloController {

private final HelloModel model = new HelloModel();

@FXML
public ListView<NtfyMessageDto> messageView ;

@FXML
private Label messageLabel;

@FXML
private TextField messageField;

@FXML
private Button emojiButton;

@FXML
private void emojis() {

String[] emojis = {"😀", "😂", "😍", "😎", "😭", "👍", "🎉"};


ContextMenu emojiMenu = new ContextMenu();
for (String emoji : emojis) {
MenuItem item = new MenuItem(emoji);
item.setOnAction(e -> {
messageField.appendText(emoji);
});
emojiMenu.getItems().add(item);
}

emojiMenu.show(emojiButton, Side.BOTTOM, 0, 0);
}

@FXML
private void initialize() {
if (messageLabel != null) {
messageLabel.setText(model.getGreeting());
messageLabel.setText(model.getGreeting());
messageView.setItems(model.getMessages());
Comment on lines +48 to +49
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Label text from FXML is overridden by greeting

initialize() sets messageLabel from model.getGreeting(), so the "CHAT LAB3" text configured in hello-view.fxml will never be visible. If the intent is to show the “CHAT LAB3” header, consider removing this assignment or using a separate label for the greeting/version info.

🤖 Prompt for AI Agents
In src/main/java/com/example/HelloController.java around lines 48-49, the
initialize() call messageLabel.setText(model.getGreeting()) overrides the static
"CHAT LAB3" text from hello-view.fxml; remove that assignment or wire a separate
Label for the dynamic greeting. Fix by either (A) delete the
messageLabel.setText(model.getGreeting()) line so the FXML header remains, or
(B) add a new @FXML Label (e.g., greetingLabel) in the FXML and controller and
set model.getGreeting() on that new label instead, or (C) only set the text when
the FXML value is empty (if conditional behavior is desired).

messageView.setCellFactory(list -> new ListCell<>() {
@Override
protected void updateItem(NtfyMessageDto msg, boolean empty) {
super.updateItem(msg, empty);

if (empty || msg == null) {
setGraphic(null);
return;
}

Label label = new Label(msg.toString());
label.setWrapText(true);
label.setMaxWidth(180);


boolean fromMe = msg.topic() != null && msg.topic().equals("me");

if (fromMe) {
label.setStyle("-fx-background-color: lightgreen; -fx-padding: 6; -fx-background-radius: 8;");
setAlignment(Pos.CENTER_RIGHT);
} else {
label.setStyle("-fx-background-color: lightgray; -fx-padding: 6; -fx-background-radius: 8;");
setAlignment(Pos.CENTER_LEFT);
}

setGraphic(label);
}
});

}



public void sendMessage(ActionEvent actionEvent) {
String text = messageField.getText().trim();
if (!text.isEmpty()) {
model.sendMessage(text);
messageField.clear();
}
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/example/HelloFX.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example;

import io.github.cdimascio.dotenv.Dotenv;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
Expand All @@ -10,6 +11,7 @@ public class HelloFX extends Application {

@Override
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);
Expand Down
79 changes: 79 additions & 0 deletions src/main/java/com/example/HelloModel.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
package com.example;

import io.github.cdimascio.dotenv.Dotenv;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import tools.jackson.databind.ObjectMapper;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

ObjectMapper import likely incorrect

The import tools.jackson.databind.ObjectMapper looks suspicious; the standard Jackson ObjectMapper class is in the com.fasterxml.jackson.databind package. With the current import this will not compile unless you have a nonstandard tools.jackson dependency.

Update the import to match the actual package provided by your Jackson version (most likely com.fasterxml.jackson.databind.ObjectMapper).


🏁 Script executed:

#!/bin/bash
# Examine the HelloModel.java file and check dependencies
echo "=== HelloModel.java imports and class structure ==="
cat src/main/java/com/example/HelloModel.java 2>/dev/null || echo "File not found at expected path"

echo ""
echo "=== Searching for pom.xml to check dependencies ==="
find . -name "pom.xml" -type f | head -5

echo ""
echo "=== Searching for build.gradle to check dependencies ==="
find . -name "build.gradle*" -type f | head -5

Length of output: 3772


🏁 Script executed:

#!/bin/bash
# Check pom.xml for Jackson dependencies
echo "=== pom.xml Jackson dependencies ==="
cat pom.xml

Length of output: 3021


ObjectMapper import is incompatible with the declared dependency

The import tools.jackson.databind.ObjectMapper does not match the Jackson dependency declared in pom.xml. The dependency specifies:

<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>

The groupId is tools.jackson.core, not tools.jackson.databind. This will cause a compilation error.

Additionally, tools.jackson.core is a nonstandard groupId. The official Jackson library from FasterXML uses com.fasterxml.jackson.core.

Fix: Update pom.xml to use the standard Jackson dependency:

<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>

Then update the import to import com.fasterxml.jackson.databind.ObjectMapper;

🤖 Prompt for AI Agents
In src/main/java/com/example/HelloModel.java around line 7, the current import
uses tools.jackson.databind.ObjectMapper which is incompatible with the declared
dependency and nonstandard; update the project's pom.xml to use the standard
Jackson groupId com.fasterxml.jackson.core with artifactId jackson-databind
(replace tools.jackson.core groupId if present), then change the import in this
file to import com.fasterxml.jackson.databind.ObjectMapper; ensure you
refresh/rebuild dependencies after updating pom.xml.


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;

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

private final String hostName;
private final HttpClient http = HttpClient.newHttpClient();
private final ObjectMapper mapper = new ObjectMapper();
private final ObservableList<NtfyMessageDto> messages = FXCollections.observableArrayList();

private boolean senderMe=false;

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

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

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

public void sendMessage(String text) {

senderMe=true;

long now = System.currentTimeMillis() / 1000;
NtfyMessageDto myMsg = new NtfyMessageDto("local", now, "message", "me", text);

Platform.runLater(() -> messages.add(myMsg));

HttpRequest httpRequest= HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(text))
.uri(URI.create(hostName + "/mytopic"))
.build();
http.sendAsync(httpRequest, HttpResponse.BodyHandlers.discarding())
.exceptionally(ex -> {
System.out.println("Error sending message: " + ex.getMessage());
return null;
});
}

public void receiveMessage(){
HttpRequest httpRequest = HttpRequest.newBuilder()
.GET()
.uri(URI.create(hostName + "/mytopic/json"))
.build();

http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
.thenAccept(response -> response.body()
.map(s -> {
try {
return mapper.readValue(s, NtfyMessageDto.class);
} catch (Exception e) {
System.err.println("Failed to parse message: " + e.getMessage());
return null;
}
})
.filter(Objects::nonNull)
.filter(msg -> "message".equals(msg.event()))
.forEach(msg->{
if (senderMe) {
senderMe=false;
return;
}
Platform.runLater(() -> messages.add(msg));
}));
}

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

public class ManyParameters {

public ManyParameters(String computerName, int timeout, String method, int size, byte[] data) {

}
Comment on lines +5 to +7
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Constructor body is empty - parameters are not stored.

The constructor accepts five parameters but the body is empty, meaning all parameters are discarded. The class also has no fields to store this data. This renders the class non-functional.

Add fields and assign the constructor parameters:

 public class ManyParameters {
+    private final String computerName;
+    private final int timeout;
+    private final String method;
+    private final int size;
+    private final byte[] data;

     public ManyParameters(String computerName, int timeout, String method, int size, byte[] data) {
-
+        this.computerName = computerName;
+        this.timeout = timeout;
+        this.method = method;
+        this.size = size;
+        this.data = data;
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/example/ManyParameters.java around lines 5 to 7, the
constructor currently has no body and there are no fields to retain the passed
values; add private fields for computerName (String), timeout (int), method
(String), size (int) and data (byte[]) to the class and assign each constructor
parameter to its corresponding field (use defensive copy for the byte[] if
immutability is desired). Ensure fields are appropriately scoped (e.g., private
final if immutable) and consider validating/null-checking parameters before
assignment.


static void main () {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Incorrect main method signature.

The method signature should be public static void main(String[] args) to be recognized as a valid Java program entry point. The current signature static void main() won't work.

Apply this diff:

-    static void main () {
+    public static void main(String[] args) {
📝 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
static void main () {
public static void main(String[] args) {
🤖 Prompt for AI Agents
In src/main/java/com/example/ManyParameters.java around line 9, the main method
currently has the signature "static void main()" which is not a valid Java entry
point; change it to the standard public static void main(String[] args)
signature so the JVM can recognize and invoke it, updating visibility to public
and adding the String[] args parameter.


ManyParametersBuilder builder= new ManyParametersBuilder();
builder
.setComputerName("localhost")
.setTimeout(10)
.setSize(0)
.createManyParameters();
}


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

public class ManyParametersBuilder {
private String computerName;
private int timeout = 0;
private String method;
private int size = 0;
private byte[] data = null;

public ManyParametersBuilder setComputerName(String computerName) {
this.computerName = computerName;
return this;
}

public ManyParametersBuilder setTimeout(int timeout) {
this.timeout = timeout;
return this;
}

public ManyParametersBuilder setMethod(String method) {
this.method = method;
return this;
}

public ManyParametersBuilder setSize(int size) {
this.size = size;
return this;
}

public ManyParametersBuilder setData(byte[] data) {
this.data = data;
return this;
}
Comment on lines +30 to +33
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing defensive copy for mutable byte array.

The data array is stored directly without making a defensive copy. This allows external code to modify the array after passing it to the builder, breaking encapsulation.

Apply this diff to create a defensive copy:

     public ManyParametersBuilder setData(byte[] data) {
-        this.data = data;
+        this.data = data != null ? data.clone() : null;
         return this;
     }
🤖 Prompt for AI Agents
In src/main/java/com/example/ManyParametersBuilder.java around lines 30 to 33,
the setData(byte[] data) method stores the incoming mutable array directly;
change it to make a defensive copy (e.g., this.data = data == null ? null :
Arrays.copyOf(data, data.length)) and ensure you import java.util.Arrays; also
audit any getter or build method that exposes this.data and return a copy there
as well to preserve encapsulation.


public ManyParameters createManyParameters() {
return new ManyParameters(computerName, timeout, method, size, data);
}
}
20 changes: 20 additions & 0 deletions src/main/java/com/example/NtfyMessageDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@JsonIgnoreProperties(ignoreUnknown = true)
public record NtfyMessageDto(String id, long time, String event, String topic, String message){
private static final DateTimeFormatter date =
DateTimeFormatter.ofPattern("HH:mm");
@Override
public String toString(){
String timeStr = new SimpleDateFormat("HH:mm").format(new Date(time * 1000));
return timeStr+ " " + message ;
}


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

public class Singelton {

private final static Singelton instance= new Singelton();

public static Singelton getInstance(){
return instance;
}

}
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
27 changes: 20 additions & 7 deletions src/main/resources/com/example/hello-view.fxml
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
<?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 prefHeight="482.0" prefWidth="248.0" spacing="5.0" xmlns="http://javafx.com/javafx/17.0.12" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.HelloController">
<Label fx:id="messageLabel" />
<ListView fx:id="messageView" prefHeight="373.0" prefWidth="248.0" VBox.vgrow="ALWAYS" />

<HBox spacing="5.0">
<Button fx:id="emojiButton" onAction="#emojis" prefHeight="25.0" prefWidth="34.0" text="😀" />
<TextField fx:id="messageField" prefHeight="50.0" prefWidth="154.0" promptText="Type your message..." HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets bottom="5.0" />
</HBox.margin></TextField>
<Button onAction="#sendMessage" prefHeight="34.0" prefWidth="43.0" text="Send">
<HBox.margin>
<Insets right="2.0" />
</HBox.margin></Button>
</HBox>
</VBox>
Loading