Skip to content

Commit 20ca18a

Browse files
committed
Implemented sending message
1 parent 83dbcef commit 20ca18a

5 files changed

Lines changed: 78 additions & 13 deletions

File tree

src/main/java/com/example/HelloController.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,56 @@
33
import javafx.event.ActionEvent;
44
import javafx.fxml.FXML;
55
import javafx.scene.control.Label;
6+
import javafx.scene.control.ListCell;
67
import javafx.scene.control.ListView;
8+
import javafx.scene.control.TextField;
79

810
/**
911
* Controller layer: mediates between the view (FXML) and the model.
1012
*/
1113
public class HelloController {
1214

1315
private final HelloModel model = new HelloModel(new NtfyConnectionImpl());
16+
17+
@FXML
1418
public ListView<NtfyMessageDto> messageView;
1519

1620
@FXML
1721
private Label messageLabel;
1822

23+
@FXML
24+
private TextField messageInput;
25+
1926
@FXML
2027
private void initialize() {
2128
if (messageLabel != null) {
2229
messageLabel.setText(model.getGreeting());
2330
}
2431
messageView.setItems(model.getMessages());
2532

33+
if (messageInput != null) {
34+
messageInput.textProperty().bindBidirectional(model.messageToSendProperty());
35+
}
36+
37+
messageView.setCellFactory(param -> new ListCell<>() {
38+
@Override
39+
protected void updateItem(NtfyMessageDto item, boolean empty) {
40+
super.updateItem(item, empty);
41+
42+
if (empty || item == null) {
43+
setText(null);
44+
} else {
45+
var time = java.time.Instant.ofEpochSecond(item.time())
46+
.atZone(java.time.ZoneId.systemDefault())
47+
.toLocalTime();
48+
var formatter = java.time.format.DateTimeFormatter.ofPattern("HH:mm");
49+
setText(time.format(formatter) + " " + item.message());
50+
}
51+
}
52+
});
2653
}
2754

55+
2856
public void sendMessage(ActionEvent actionEvent) {
2957
model.sendMessage();
3058
}

src/main/java/com/example/HelloModel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ public String getGreeting() {
5757
return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".";
5858
}
5959
public void sendMessage() {
60-
connection.sendMessage(messageToSend.get());
60+
String msg = messageToSend.get();
61+
if (msg != null && !msg.isBlank()) {
62+
connection.sendMessage(msg);
63+
}
6164
}
6265

6366
public void receiveMessage() {

src/main/java/com/example/NtfyConnectionImpl.java

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,25 @@ public boolean sendMessage(String message) {
3232
//Todo: Send message using HTTPClient
3333

3434
HttpRequest httpRequest = HttpRequest.newBuilder()
35-
.POST(HttpRequest.BodyPublishers.ofString("Hello World"))
35+
.POST(HttpRequest.BodyPublishers.ofString(message))
3636
.uri(URI.create(hostName + "/mytopic"))
3737
.build();
3838
try {
3939
//Todo: handle long blocking send requests to not freeze the JavaFX thread
4040
//1. Use thread send message?
4141
//2. Use async?
4242
var response = http.send(httpRequest, HttpResponse.BodyHandlers.ofString());
43+
if (response.statusCode() != 200) {
44+
System.err.println("Failed to send message. HTTP Status: " + response.statusCode());
45+
System.err.println("Response body: " + response.body());
46+
return false;
47+
}
4348
return true;
4449
} catch (IOException e) {
45-
System.out.println("Error sending message");
50+
System.err.println("Network I/O error sending message: " + e.getMessage());
4651
} catch (InterruptedException e) {
47-
System.out.println("Interrupted");
52+
System.err.println("Send message operation interrupted");
53+
Thread.currentThread().interrupt();
4854
}
4955
return false;
5056
}
@@ -58,11 +64,34 @@ public void receiveMessage(Consumer<NtfyMessageDto> messageHandler) {
5864
.build();
5965

6066
http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
61-
.thenAccept(response -> response.body()
62-
.map(s ->
63-
mapper.readValue(s, NtfyMessageDto.class))
64-
.filter(message -> message.event().equals("message"))
65-
.peek(System.out::println)
66-
.forEach(messageHandler));
67+
.thenAccept(response -> {
68+
if (response.statusCode() != 200) {
69+
System.err.println("Error connecting to stream. HTTP Status: " + response.statusCode());
70+
return;
71+
}
72+
response.body()
73+
.map(s -> {
74+
try {
75+
return mapper.readValue(s, NtfyMessageDto.class);
76+
} catch (Exception e) {
77+
System.err.println("Failed to parse JSON: " + e.getMessage());
78+
return null;
79+
}
80+
})
81+
.filter(Objects::nonNull)
82+
.filter(message -> "message".equals(message.event()))
83+
.peek(m -> {
84+
var time = java.time.Instant.ofEpochSecond(m.time())
85+
.atZone(java.time.ZoneId.systemDefault())
86+
.toLocalTime();
87+
System.out.println(time + " " + m.message());
88+
})
89+
.forEach(messageHandler);
90+
}).exceptionally(e -> {
91+
System.err.println("Async connection error: " + e.getMessage());
92+
e.printStackTrace();
93+
return null;
94+
});
6795
}
6896
}
97+

src/main/resources/com/example/hello-view.fxml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
<?import javafx.scene.layout.VBox?>
66
<?import javafx.scene.control.Button?>
77
<?import javafx.scene.control.ListView?>
8+
<?import javafx.scene.control.TextField?>
89
<VBox alignment="CENTER" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.HelloController">
910
<Label fx:id="messageLabel" text="Hello, JavaFX!" />
1011
<Button text="Send message" onAction="#sendMessage"/>
1112
<ListView fx:id="messageView"/>
13+
<TextField fx:id="messageInput"/>
1214
</VBox>

src/test/java/com/example/HelloModelTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ void sendMessageCallsConnectionWithMessageToSend() {
2828

2929
@Test
3030
void sendMessageToFakeServer(WireMockRuntimeInfo wireMockRuntimeInfo) {
31+
stubFor(get(urlPathMatching("/mytopic/json.*")).willReturn(ok()));
32+
33+
stubFor(post("/mytopic").willReturn(ok()));
34+
3135
var con = new NtfyConnectionImpl("http://localhost:" + wireMockRuntimeInfo.getHttpPort());
3236
var model = new HelloModel(con);
3337
model.setMessageToSend("Hello World");
34-
stubFor(post("/mytopic").willReturn(ok()));
3538

3639
model.sendMessage();
3740

38-
//Verify call made to server
39-
verify(postRequestedFor(urlEqualTo("/mytopic")).withRequestBody(containing("Hello World")));
41+
verify(postRequestedFor(urlEqualTo("/mytopic"))
42+
.withRequestBody(containing("Hello World")));
4043
}
4144
}

0 commit comments

Comments
 (0)