Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
target/
/.idea/
.env
package-lock.json
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>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.2.0</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
12 changes: 10 additions & 2 deletions src/main/java/com/example/HelloController.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package com.example;

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

/**
* 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;
Expand All @@ -18,5 +20,11 @@ private void initialize() {
if (messageLabel != null) {
messageLabel.setText(model.getGreeting());
}
messageView.setItems(model.getMessages());

}

public void sendMessage(ActionEvent actionEvent) {
model.sendMessage();
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/example/HelloFX.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
package com.example;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
Expand All @@ -13,7 +12,7 @@ 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");
stage.setTitle("Chatt Client");
stage.setScene(scene);
stage.show();
}
Expand Down
46 changes: 43 additions & 3 deletions src/main/java/com/example/HelloModel.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,55 @@
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();

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

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

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

public StringProperty messageToSendProperty() {
return messageToSend;
}

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

/**
* 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 + ".";
return "Chat Client by Adam";
}

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

}

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

public class ManyParameters {

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

}

static void main(){
ManyParametersBuilder builder = new ManyParametersBuilder();
builder
.setComputerName("localhost") // Fluent API
.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;
}

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

import java.util.function.Consumer;

public interface NtfyConnection {
public boolean send(String message);

public void receive(Consumer<NtfyMessageDto> messageHandler);
}
62 changes: 62 additions & 0 deletions src/main/java/com/example/NtfyConnectionImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example;
import io.github.cdimascio.dotenv.Dotenv;
import tools.jackson.databind.ObjectMapper;
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.function.Consumer;

public class NtfyConnectionImpl implements NtfyConnection {

private final HttpClient http = HttpClient.newHttpClient();
private final String hostName;
private final ObjectMapper mapper = new ObjectMapper();

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

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

@Override
public boolean send(String message) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.POST(HttpRequest.BodyPublishers.ofString(message))
.uri(URI.create(hostName + "/mytopic"))
.build();
try {
// TODO: handle long blocking send requests to not freeze the JavaFX thread
// 1. Use thread send message?
// 2. Use async?
var response = http.send(httpRequest, HttpResponse.BodyHandlers.ofString());
return true;
} catch (IOException e) {
System.out.println("Error sending message");
} catch (InterruptedException e) {
System.out.println("Interrupted sending message");
}
return false;
}

@Override
public void receive(Consumer<NtfyMessageDto> messageHandler) {
HttpRequest httpRequest = HttpRequest.newBuilder()
.GET()
.uri(URI.create(hostName + "/mytopic/json?since=wBuD2KGEaAe0"))
.build();

http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines())
.thenAccept(response -> response.body()
.map(s->
mapper.readValue(s, NtfyMessageDto.class))
.filter(message -> message.event().equals("message"))
.peek(System.out::println)
.forEach(messageHandler));
}
}
6 changes: 6 additions & 0 deletions src/main/java/com/example/NtfyMessageDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
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) {}
13 changes: 13 additions & 0 deletions src/main/java/com/example/Singelton.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example;

public class Singelton {
private final static Singelton instance = new Singelton();

private Singelton() {

}

public static Singelton getInstance() {
return instance;
}
}
4 changes: 4 additions & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
module hellofx {
requires javafx.controls;
requires javafx.fxml;
requires io.github.cdimascio.dotenv.java;
requires java.net.http;
requires tools.jackson.databind;
requires javafx.graphics;

opens com.example to javafx.fxml;
exports com.example;
Expand Down
19 changes: 11 additions & 8 deletions src/main/resources/com/example/hello-view.fxml
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<?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.scene.control.*?>
<?import javafx.scene.layout.*?>

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

<Label fx:id="messageLabel" text="Adams Chat Client" />
<Button onAction="#sendMessage" prefHeight="25.0" prefWidth="115.0" text="Send message" />
<ListView fx:id="messageView" />

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

import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;

@WireMockTest
class HelloModelTest {

@Test
@DisplayName("Given a model with messageToSend when calling sendMessage then send method on connection should be called ")
void sendMessageCallsConnectionWithMessageToSend() {

// Arrange Given
var spy = new NtfyConnectionSpy();
var model = new HelloModel(spy);
model.setMessageToSend("Hello World");

// Act When
model.sendMessage();

// Assert Then
assertThat(spy.message).isEqualTo("Hello World");
}

@Test
void sendMessageToFakeServer(WireMockRuntimeInfo wmRuntimeInfo) {
var con = new NtfyConnectionImpl("http://localhost:" + wmRuntimeInfo.getHttpPort());
var model = new HelloModel(con);
model.setMessageToSend("Hello World");
stubFor(post("/mytopic").willReturn(ok()));

model.sendMessage();

// Verify call made to server
verify(postRequestedFor(urlEqualTo("/mytopic"))
.withRequestBody(matching("Hello World")));
}

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

import java.util.function.Consumer;

public class NtfyConnectionSpy implements NtfyConnection {

String message;
@Override
public boolean send(String message) {
this.message = message;
return true;
}

@Override
public void receive(Consumer<NtfyMessageDto> messageHandler) {

}
}