diff --git a/mvnw b/mvnw old mode 100644 new mode 100755 diff --git a/pom.xml b/pom.xml index c40f667e..83565979 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,8 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.example @@ -15,7 +16,9 @@ 3.27.6 5.20.0 25 + 2.19.2 + org.junit.jupiter @@ -35,6 +38,12 @@ ${mockito.version} test + + org.wiremock + wiremock + 4.0.0-beta.15 + test + org.openjfx javafx-controls @@ -45,7 +54,28 @@ javafx-fxml ${javafx.version} + + io.github.cdimascio + dotenv-java + 3.2.0 + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + @@ -55,7 +85,7 @@ com.example.HelloFX - + javafx true @@ -66,3 +96,4 @@ + diff --git a/src/main/java/com/example/HelloController.java b/src/main/java/com/example/HelloController.java index fdd160a0..34c691d4 100644 --- a/src/main/java/com/example/HelloController.java +++ b/src/main/java/com/example/HelloController.java @@ -1,22 +1,55 @@ 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; +import javafx.stage.FileChooser; + +import java.io.File; -/** - * 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()); @FXML private Label messageLabel; + @FXML + private ListView messageView; + + @FXML + private TextField inputMessage; + @FXML private void initialize() { - if (messageLabel != null) { - messageLabel.setText(model.getGreeting()); + messageLabel.setText(model.getGreeting()); + + + messageView.setItems(model.getMessages()); + } + + @FXML + private void sendMessage(ActionEvent event) { + String text = inputMessage.getText(); + + + model.setMessageToSend(text); + model.sendMessage(); + + + inputMessage.clear(); + } + + @FXML + private void attachFile(ActionEvent event) { + FileChooser chooser = new FileChooser(); + File file = chooser.showOpenDialog(messageView.getScene().getWindow()); + if (file != null) { + model.sendFile(file); } } } + + diff --git a/src/main/java/com/example/HelloModel.java b/src/main/java/com/example/HelloModel.java index 385cfd10..a0914345 100644 --- a/src/main/java/com/example/HelloModel.java +++ b/src/main/java/com/example/HelloModel.java @@ -1,15 +1,63 @@ package com.example; -/** - * Model layer: encapsulates application data and business logic. - */ +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + public class HelloModel { - /** - * Returns a greeting based on the current Java and JavaFX versions. - */ + + private final NtfyConnection connection; + private final ObservableList messages = FXCollections.observableArrayList(); + + private String messageToSend = ""; + + public HelloModel(NtfyConnection connection) { + this.connection = connection; + + messages.add(new NtfyMessageDto("init", 0, "message", "mytopic", "Initial message")); + + receiveMessages(); + } + + public ObservableList getMessages() { + return messages; + } + + public String getMessageToSend() { + return messageToSend; + } + + public void setMessageToSend(String messageToSend) { + this.messageToSend = messageToSend; + } + + public void sendMessage() { + if (messageToSend != null && !messageToSend.isBlank()) { + connection.send(messageToSend); + } + messageToSend = ""; + } + + public void sendFile(File file) { + try { + byte[] data = Files.readAllBytes(file.toPath()); + connection.sendFile(file.getName(), data); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void receiveMessages() { + connection.receive(m -> Platform.runLater(() -> messages.add(m))); + } + public String getGreeting() { - String javaVersion = System.getProperty("java.version"); - String javafxVersion = System.getProperty("javafx.version"); - return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; + return "Hello, JavaFX!"; } } + + diff --git a/src/main/java/com/example/ManyParameters.java b/src/main/java/com/example/ManyParameters.java new file mode 100644 index 00000000..ee2e2a18 --- /dev/null +++ b/src/main/java/com/example/ManyParameters.java @@ -0,0 +1,19 @@ +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") + .setTimeout(10) + .setSize(0) + .createManyParameters(); + } +} diff --git a/src/main/java/com/example/ManyParametersBuilder.java b/src/main/java/com/example/ManyParametersBuilder.java new file mode 100644 index 00000000..fd49920d --- /dev/null +++ b/src/main/java/com/example/ManyParametersBuilder.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/NtfyConnection.java b/src/main/java/com/example/NtfyConnection.java new file mode 100644 index 00000000..deedc6dc --- /dev/null +++ b/src/main/java/com/example/NtfyConnection.java @@ -0,0 +1,33 @@ +package com.example; + +import java.util.function.Consumer; + +public interface NtfyConnection { + + /** + * Skickar ett textmeddelande till servern. + * + * @param message meddelandet som ska skickas + * @return true om det lyckades, false annars + */ + boolean send(String message); + + /** + * Registrerar en mottagare som hanterar inkommande meddelanden. + * + * @param messageHandler funktion som hanterar inkommande NtfyMessageDto + */ + void receive(Consumer messageHandler); + + /** + * Skickar en fil till servern. + * + * @param filename namnet på filen + * @param data innehållet i filen som byte-array + */ + void sendFile(String filename, byte[] data); +} + + + + diff --git a/src/main/java/com/example/NtfyConnectionImpl.java b/src/main/java/com/example/NtfyConnectionImpl.java new file mode 100644 index 00000000..98fdc9b7 --- /dev/null +++ b/src/main/java/com/example/NtfyConnectionImpl.java @@ -0,0 +1,101 @@ +package com.example; + +import io.github.cdimascio.dotenv.Dotenv; +import com.fasterxml.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(); + + 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 message) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(message)) + .header("Cache", "no") + .uri(URI.create(hostName + "/mytopic")) + .build(); + + try { + http.send(httpRequest, HttpResponse.BodyHandlers.discarding()); + return true; + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public void receive(Consumer messageHandler) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .GET() + .uri(URI.create(hostName + "/mytopic/json")) + .build(); + + try { + http.send(httpRequest, HttpResponse.BodyHandlers.ofLines()) + .body() + .map(s -> { + try { + return mapper.readValue(s, NtfyMessageDto.class); + } catch (IOException e) { + return null; + } + }) + .filter(Objects::nonNull) + .filter(message -> "message".equals(message.event())) + .forEach(messageHandler); + + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + @Override + public void sendFile(String filename, byte[] data) { + HttpRequest request = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofByteArray(data)) + .header("Content-Type", "application/octet-stream") + .header("Title", filename) + .uri(URI.create(hostName + "/mytopic")) + .build(); + + try { + http.send(request, HttpResponse.BodyHandlers.discarding()); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public void sendAsync(String message) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(message)) + .header("Cache", "no") + .uri(URI.create(hostName + "/mytopic")) + .build(); + + http.sendAsync(httpRequest, HttpResponse.BodyHandlers.discarding()) + .thenAccept(response -> System.out.println("Message sent async")) + .exceptionally(e -> { e.printStackTrace(); return null; }); + } +} + + diff --git a/src/main/java/com/example/NtfyMessageDto.java b/src/main/java/com/example/NtfyMessageDto.java new file mode 100644 index 00000000..697cccac --- /dev/null +++ b/src/main/java/com/example/NtfyMessageDto.java @@ -0,0 +1,7 @@ +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) { +} \ No newline at end of file diff --git a/src/main/java/com/example/Singelton.java b/src/main/java/com/example/Singelton.java new file mode 100644 index 00000000..b3685a01 --- /dev/null +++ b/src/main/java/com/example/Singelton.java @@ -0,0 +1,14 @@ +package com.example; + +public class Singelton { + + private final static Singelton instance = new Singelton(); + + private Singelton(){ + + } + + public static Singelton getInstance(){ + return instance; + } +} \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 71574a27..bef07b70 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,10 @@ module hellofx { requires javafx.controls; requires javafx.fxml; + requires io.github.cdimascio.dotenv.java; + requires java.net.http; + requires javafx.graphics; + requires com.fasterxml.jackson.databind; opens com.example to javafx.fxml; exports com.example; diff --git a/src/main/resources/background.png b/src/main/resources/background.png new file mode 100644 index 00000000..65e8e29a Binary files /dev/null and b/src/main/resources/background.png differ diff --git a/src/main/resources/com/example/hello-view.fxml b/src/main/resources/com/example/hello-view.fxml index 20a7dc82..bfed5722 100644 --- a/src/main/resources/com/example/hello-view.fxml +++ b/src/main/resources/com/example/hello-view.fxml @@ -1,9 +1,28 @@ - + + + + - - - - + + + + +