Skip to content
Open
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
61 changes: 51 additions & 10 deletions src/main/java/com/example/HelloController.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,63 @@
package com.example;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.application.Platform;

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

// Kopplas till FXML-filen
@FXML private TextField inputField;
@FXML private Button sendBtn;
@FXML private ListView<String> messages;

// Skapar modellen som sköter nätverksdelen (skicka/ta emot)
private final HelloModel model = new HelloModel();

// Körs automatiskt när appen startar
@FXML
private Label messageLabel;
public void initialize() {
// Starttext när programmet öppnas
messages.getItems().add("Ansluten till: " + model.info());
messages.getItems().add("Skriv ett meddelande och tryck Skicka!");

@FXML
private void initialize() {
if (messageLabel != null) {
messageLabel.setText(model.getGreeting());
// Börja lyssna efter inkommande meddelanden
startListeningToMessages();

// När man trycker på Skicka-knappen
sendBtn.setOnAction(_ -> sendMessage());
}
Comment on lines +29 to +31
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

❓ Verification inconclusive

Lambda parameter _ is not valid in modern Java versions

On Line 30, sendBtn.setOnAction(_ -> sendMessage()); uses _ as the lambda parameter name. In Java 9+ _ is a reserved identifier and this will fail to compile. Use a conventional name instead, e.g.:

-        sendBtn.setOnAction(_ -> sendMessage());
+        sendBtn.setOnAction(event -> sendMessage());

Lambda parameter _ is not valid in modern Java versions

On Line 30, sendBtn.setOnAction(_ -> sendMessage()); uses _ as the lambda parameter name. In Java 9+, it is a compile-time error if a lambda parameter has the name _. This restriction was introduced in Java 9. Use a conventional name instead, e.g.:

-        sendBtn.setOnAction(_ -> sendMessage());
+        sendBtn.setOnAction(event -> sendMessage());
🤖 Prompt for AI Agents
In src/main/java/com/example/HelloController.java around lines 29 to 31, the
lambda uses `_` as the parameter name which is a compile-time error in Java 9+;
replace the underscore with a valid identifier (for example `e`, `event`, or
`actionEvent`) or use a no-arg lambda form if appropriate, e.g. change
`sendBtn.setOnAction(_ -> sendMessage());` to `sendBtn.setOnAction(e ->
sendMessage());` so the code compiles on modern Java versions.


// Skickar ett meddelande till chatten
private void sendMessage() {
String text = inputField.getText();

if (text == null || text.isBlank()) {
return; // Skicka inte tomt meddelande
}

// Visa direkt i listan
messages.getItems().add("Jag: " + text);

// Skicka till servern
model.sendMessage(text);

// Töm textfältet
inputField.clear();
}

// Lyssnar efter nya meddelanden i bakgrunden
private void startListeningToMessages() {
model.startListening(
// När ett nytt meddelande kommer
msg -> Platform.runLater(() ->messages.getItems().add("Inkommande: " + msg)
),

//Om ett fel inträffar
err -> Platform.runLater(() ->messages.getItems().add("Fel: " + err.getMessage())
)
);
}
}
}
72 changes: 61 additions & 11 deletions src/main/java/com/example/HelloModel.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,65 @@
package com.example;

/**
* Model layer: encapsulates application data and business logic.
*/
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.function.Consumer;

public class HelloModel {
/**
* Returns a greeting based on the current Java and JavaFX versions.
*/
public String getGreeting() {
String javaVersion = System.getProperty("java.version");
String javafxVersion = System.getProperty("javafx.version");
return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".";
private final String baseUrl = "https://ntfy.sh";
private final String topic = "java25-erika-chat";

// Skickar ett textmeddelande till ntfy
public void sendMessage(String message) {
try {
var url = new URL(baseUrl + "/" + topic);
var conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");
conn.setDoOutput(true);

conn.getOutputStream().write(message.getBytes());

System.out.println("Skickat till " + url + ": " + message);
conn.disconnect();
} catch (Exception e) {
System.out.println("Något gick fel: " + e.getMessage());
}
}

// Startar en tråd som lyssnar efter nya meddelanden
public void startListening(Consumer<String> onMessage, Consumer<Throwable> onError) {
new Thread(() -> {
try {
var url = new URL(baseUrl + "/" + topic + "/json");
var conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");

var reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;

while ((line = reader.readLine()) != null) {
// Plocka ut texten mellan "message":" och nästa "
int start = line.indexOf("\"message\":\"");
if (start != -1) {
start += 11;
int end = line.indexOf("\"", start);
if (end != -1) {
String msg = line.substring(start, end);
if (onMessage != null) onMessage.accept(msg);
}
}
}

} catch (Throwable ex) {
if (onError != null) onError.accept(ex);
}
}).start();
}

// Visar vilken topic och url som används
public String info() {
return baseUrl + "/" + topic;
}
}
}
37 changes: 29 additions & 8 deletions src/main/resources/com/example/hello-view.fxml
Original file line number Diff line number Diff line change
@@ -1,9 +1,30 @@
<?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>

<!-- Enkel chattvy med lista, textfält och knapp -->
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.*?>
<?import javafx.geometry.Insets?>

<BorderPane xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.HelloController">

<!-- Meddelandelista -->
<center>
<ListView fx:id="messages"/>
</center>

<!-- Textfält och knapp -->
<bottom>
<HBox spacing="8" alignment="CENTER_LEFT">
<TextField fx:id="inputField" promptText="Skriv ett meddelande..." HBox.hgrow="ALWAYS"/>
<Button fx:id="sendBtn" text="Skicka" defaultButton="true"/>
</HBox>
</bottom>

<!-- Luft runt hela layouten -->
<padding>
<Insets topRightBottomLeft="8"/>
</padding>

</BorderPane>
26 changes: 26 additions & 0 deletions src/test/java/com/example/HelloModelTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

public class HelloModelTest {

@Test
void info_returnsCorrectUrl() {
HelloModel model = new HelloModel();
assertEquals("https://ntfy.sh/java25-erika-chat", model.info());
}

@Test
void sendMessage_doesNotThrow() {
HelloModel model = new HelloModel();
assertDoesNotThrow(() -> model.sendMessage("test"));
}

@Test
void startListening_doesNotThrow() {
HelloModel model = new HelloModel();
assertDoesNotThrow(() -> model.startListening(msg -> {}, err -> {}));
}
Comment on lines +21 to +25
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

🧩 Analysis chain

startListening_doesNotThrow can leak a long‑running background thread

startListening starts a new non‑daemon thread that blocks on reader.readLine() against the live ntfy endpoint. The test only asserts the call does not throw; it does not wait for or stop the listener. This can:

  • Leave a background thread running after the test finishes, and
  • Make tests depend on external network availability.

Consider either:

  • Refactoring HelloModel so the listener thread can be stopped (and doing that in the test), or
  • Abstracting the network layer so the test can run against a stub instead of the real ntfy service.

I'll verify the review comment by examining the codebase to understand the actual implementation of HelloModel and the test setup.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find HelloModel class
fd -type f -name "HelloModel.java"

Length of output: 170


🏁 Script executed:

#!/bin/bash
# Search for startListening method definition and usage
rg -n "startListening" --type=java -C 5

Length of output: 3648


🏁 Script executed:

#!/bin/bash
# Check for test lifecycle methods in HelloModelTest.java
rg -n "@Before|@After|@BeforeEach|@AfterEach" src/test/java/com/example/HelloModelTest.java -C 3

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for thread creation and daemon status
rg -n "new Thread|setDaemon|Thread\(" --type=java -C 4

Length of output: 786


🏁 Script executed:

#!/bin/bash
# Check HelloModelTest.java structure for any listeners or cleanup
cat src/test/java/com/example/HelloModelTest.java

Length of output: 730


I need to see the complete startListening() implementation to confirm the thread behavior:


---

🏁 Script executed:

```shell
#!/bin/bash
# View full HelloModel.java file
cat src/main/java/com/example/HelloModel.java

Length of output: 2241


Fix the thread leak in startListening_doesNotThrow by implementing listener cleanup

The issue is confirmed: HelloModel.startListening() creates a non-daemon thread that blocks indefinitely on reader.readLine() against the live ntfy endpoint (line 42 in src/main/java/com/example/HelloModel.java). The test starts this listener but never stops it, leaving a background thread running after the test completes.

Recommended fixes:

  1. Refactor HelloModel.startListening() to return a Closeable or AutoCloseable reference so tests can stop the listener, then use try-with-resources in the test.
  2. Mock or stub the HTTP layer in tests to avoid external network dependencies and eliminate the blocking I/O.

}
Loading