From 465ed20efa77d0632d0f20390a567a70306451bc Mon Sep 17 00:00:00 2001 From: kske Date: Tue, 8 Sep 2020 20:41:01 +0200 Subject: [PATCH] Replace the internal event bus with Event Bus 0.0.3 The Event class has been retrofitted to implement IEvent, so that no event implementations had to be changed. --- .../envoy/client/event/ThemeChangeEvent.java | 11 +- .../main/java/envoy/client/net/Client.java | 53 +++-- .../GroupMessageStatusChangeProcessor.java | 4 +- .../net/MessageStatusChangeProcessor.java | 3 +- .../net/ReceivedGroupMessageProcessor.java | 3 +- .../client/net/ReceivedMessageProcessor.java | 3 +- .../java/envoy/client/ui/SceneContext.java | 13 +- .../java/envoy/client/ui/StatusTrayIcon.java | 22 +- .../envoy/client/ui/controller/ChatScene.java | 205 ++++++++++-------- .../ui/controller/ContactSearchTab.java | 46 ++-- .../ui/controller/GroupCreationTab.java | 19 +- .../client/ui/controller/LoginScene.java | 21 +- .../client/ui/settings/BugReportPane.java | 3 +- .../ui/settings/GeneralSettingsPane.java | 8 +- .../client/ui/settings/UserSettingsPane.java | 18 +- client/src/main/java/module-info.java | 15 +- common/pom.xml | 13 ++ common/src/main/java/envoy/event/Event.java | 8 +- .../src/main/java/envoy/event/EventBus.java | 82 ------- common/src/main/java/module-info.java | 1 + server/src/main/java/module-info.java | 1 - 21 files changed, 253 insertions(+), 299 deletions(-) delete mode 100644 common/src/main/java/envoy/event/EventBus.java diff --git a/client/src/main/java/envoy/client/event/ThemeChangeEvent.java b/client/src/main/java/envoy/client/event/ThemeChangeEvent.java index 1572b7a..eac0afa 100644 --- a/client/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/client/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -10,16 +10,7 @@ import envoy.event.Event; * @author Kai S. K. Engelbart * @since Envoy Client v0.2-alpha */ -public final class ThemeChangeEvent extends Event { +public final class ThemeChangeEvent extends Event.Valueless { private static final long serialVersionUID = 0L; - - /** - * Initializes a {@link ThemeChangeEvent} conveying information about the change - * of the theme currently in use. - * - * @param theme the name of the new theme - * @since Envoy Client v0.2-alpha - */ - public ThemeChangeEvent(String theme) { super(theme); } } diff --git a/client/src/main/java/envoy/client/net/Client.java b/client/src/main/java/envoy/client/net/Client.java index 2cecde8..0db67eb 100644 --- a/client/src/main/java/envoy/client/net/Client.java +++ b/client/src/main/java/envoy/client/net/Client.java @@ -1,20 +1,19 @@ package envoy.client.net; -import java.io.Closeable; -import java.io.IOException; +import java.io.*; import java.net.Socket; import java.util.concurrent.TimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.logging.*; import envoy.client.data.*; import envoy.client.event.SendEvent; import envoy.data.*; import envoy.event.*; -import envoy.event.contact.ContactOperation; -import envoy.event.contact.UserSearchResult; -import envoy.util.EnvoyLog; -import envoy.util.SerializationUtils; +import envoy.event.Event; +import envoy.event.contact.*; +import envoy.util.*; + +import dev.kske.eventbus.*; /** * Establishes a connection to the server, performs a handshake and delivers @@ -29,7 +28,7 @@ import envoy.util.SerializationUtils; * @author Leon Hofmeister * @since Envoy Client v0.1-alpha */ -public final class Client implements Closeable { +public final class Client implements EventListener, Closeable { // Connection handling private Socket socket; @@ -45,6 +44,15 @@ public final class Client implements Closeable { private static final Logger logger = EnvoyLog.getLogger(Client.class); private static final EventBus eventBus = EventBus.getInstance(); + /** + * Constructs a client and registers it as an event listener. + * + * @since Envoy Client v0.2-beta + */ + public Client() { + eventBus.registerListener(this); + } + /** * Enters the online mode by acquiring a user ID from the server. As a * connection has to be established and a handshake has to be made, this method @@ -164,22 +172,14 @@ public final class Client implements Closeable { // Process ProfilePicChanges receiver.registerProcessor(ProfilePicChange.class, eventBus::dispatch); - // Process requests to not send any more attachments as they will not be shown to + // Process requests to not send any more attachments as they will not be shown + // to // other users receiver.registerProcessor(NoAttachments.class, eventBus::dispatch); // Process group creation results - they might have been disabled on the server receiver.registerProcessor(GroupCreationResult.class, eventBus::dispatch); - // Send event - eventBus.register(SendEvent.class, evt -> { - try { - sendEvent(evt.get()); - } catch (final IOException e) { - logger.log(Level.WARNING, "An error occurred when trying to send " + evt, e); - } - }); - // Request a generator if none is present or the existing one is consumed if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext()) requestIdGenerator(); @@ -219,6 +219,21 @@ public final class Client implements Closeable { writeObject(new IDGeneratorRequest()); } + /** + * Sends the value of a send event to the server. + * + * @param evt the send event to extract the value from + * @since Envoy Client v0.2-beta + */ + @dev.kske.eventbus.Event + private void onSendEvent(SendEvent evt) { + try { + sendEvent(evt.get()); + } catch (final IOException e) { + logger.log(Level.WARNING, "An error occurred when trying to send " + evt, e); + } + } + @Override public void close() throws IOException { if (online) socket.close(); } diff --git a/client/src/main/java/envoy/client/net/GroupMessageStatusChangeProcessor.java b/client/src/main/java/envoy/client/net/GroupMessageStatusChangeProcessor.java index 6f70ad6..cd365d7 100644 --- a/client/src/main/java/envoy/client/net/GroupMessageStatusChangeProcessor.java +++ b/client/src/main/java/envoy/client/net/GroupMessageStatusChangeProcessor.java @@ -4,10 +4,11 @@ import java.util.function.Consumer; import java.util.logging.Logger; import envoy.data.Message.MessageStatus; -import envoy.event.EventBus; import envoy.event.GroupMessageStatusChange; import envoy.util.EnvoyLog; +import dev.kske.eventbus.EventBus; + /** * Project: envoy-client
* File: GroupMessageStatusChangePocessor.java
@@ -25,5 +26,4 @@ public final class GroupMessageStatusChangeProcessor implements Consumerenvoy-client
* File: MessageStatusChangeProcessor.java
diff --git a/client/src/main/java/envoy/client/net/ReceivedGroupMessageProcessor.java b/client/src/main/java/envoy/client/net/ReceivedGroupMessageProcessor.java index 215c031..297bedc 100644 --- a/client/src/main/java/envoy/client/net/ReceivedGroupMessageProcessor.java +++ b/client/src/main/java/envoy/client/net/ReceivedGroupMessageProcessor.java @@ -6,9 +6,10 @@ import java.util.logging.Logger; import envoy.client.event.MessageCreationEvent; import envoy.data.GroupMessage; import envoy.data.Message.MessageStatus; -import envoy.event.EventBus; import envoy.util.EnvoyLog; +import dev.kske.eventbus.EventBus; + /** * Project: envoy-client
* File: ReceivedGroupMessageProcessor.java
diff --git a/client/src/main/java/envoy/client/net/ReceivedMessageProcessor.java b/client/src/main/java/envoy/client/net/ReceivedMessageProcessor.java index 9cb6957..955b9b9 100644 --- a/client/src/main/java/envoy/client/net/ReceivedMessageProcessor.java +++ b/client/src/main/java/envoy/client/net/ReceivedMessageProcessor.java @@ -5,7 +5,8 @@ import java.util.function.Consumer; import envoy.client.event.MessageCreationEvent; import envoy.data.Message; import envoy.data.Message.MessageStatus; -import envoy.event.EventBus; + +import dev.kske.eventbus.EventBus; /** * Project: envoy-client
diff --git a/client/src/main/java/envoy/client/ui/SceneContext.java b/client/src/main/java/envoy/client/ui/SceneContext.java index c25d525..2d693af 100644 --- a/client/src/main/java/envoy/client/ui/SceneContext.java +++ b/client/src/main/java/envoy/client/ui/SceneContext.java @@ -6,15 +6,15 @@ import java.util.logging.Level; import javafx.application.Platform; import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; -import javafx.scene.Scene; +import javafx.scene.*; import javafx.stage.Stage; import envoy.client.data.Settings; import envoy.client.event.ThemeChangeEvent; -import envoy.event.EventBus; import envoy.util.EnvoyLog; +import dev.kske.eventbus.*; + /** * Manages a stack of scenes. The most recently added scene is displayed inside * a stage. When a scene is removed from the stack, its predecessor is @@ -30,7 +30,7 @@ import envoy.util.EnvoyLog; * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ -public final class SceneContext { +public final class SceneContext implements EventListener { /** * Contains information about different scenes and their FXML resource files. @@ -84,7 +84,7 @@ public final class SceneContext { */ public SceneContext(Stage stage) { this.stage = stage; - EventBus.getInstance().register(ThemeChangeEvent.class, theme -> applyCSS()); + EventBus.getInstance().registerListener(this); } /** @@ -152,6 +152,9 @@ public final class SceneContext { } } + @Event(priority = 150, eventType = ThemeChangeEvent.class) + private void onThemeChange() { applyCSS(); } + /** * @param the type of the controller * @return the controller used by the current scene diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index 6d51955..c4b995a 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -8,7 +8,9 @@ import javafx.stage.Stage; import envoy.client.event.MessageCreationEvent; import envoy.data.Message; -import envoy.event.EventBus; + +import dev.kske.eventbus.*; +import dev.kske.eventbus.Event; /** * Project: envoy-client
@@ -18,7 +20,7 @@ import envoy.event.EventBus; * @author Kai S. K. Engelbart * @since Envoy Client v0.2-alpha */ -public final class StatusTrayIcon { +public final class StatusTrayIcon implements EventListener { /** * The {@link TrayIcon} provided by the System Tray API for controlling the @@ -67,14 +69,7 @@ public final class StatusTrayIcon { trayIcon.addActionListener(evt -> Platform.runLater(() -> { stage.setIconified(false); stage.toFront(); stage.requestFocus(); })); // Start processing message events - EventBus.getInstance().register(MessageCreationEvent.class, evt -> { - if (displayMessages) trayIcon - .displayMessage( - evt.get().hasAttachment() ? "New " + evt.get().getAttachment().getType().toString().toLowerCase() + " message received" - : "New message received", - evt.get().getText(), - MessageType.INFO); - }); + EventBus.getInstance().registerListener(this); } /** @@ -94,4 +89,11 @@ public final class StatusTrayIcon { * @since Envoy Client v0.2-beta */ public void hide() { SystemTray.getSystemTray().remove(trayIcon); } + + @Event + private void onMessageCreation(MessageCreationEvent evt) { + if (displayMessages) trayIcon + .displayMessage(evt.get().hasAttachment() ? "New " + evt.get().getAttachment().getType().toString().toLowerCase() + " message received" + : "New message received", evt.get().getText(), MessageType.INFO); + } } diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index d2b2184..e8f5c61 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -1,7 +1,5 @@ package envoy.client.ui.controller; -import static envoy.data.Message.MessageStatus.RECEIVED; - import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.io.*; @@ -36,11 +34,15 @@ import envoy.client.ui.listcell.*; import envoy.client.util.ReflectionUtil; import envoy.data.*; import envoy.data.Attachment.AttachmentType; +import envoy.data.Message.MessageStatus; import envoy.event.*; import envoy.event.contact.ContactOperation; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; +import dev.kske.eventbus.*; +import dev.kske.eventbus.Event; + /** * Project: envoy-client
* File: ChatSceneController.java
@@ -49,7 +51,7 @@ import envoy.util.EnvoyLog; * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ -public final class ChatScene implements Restorable { +public final class ChatScene implements EventListener, Restorable { @FXML private GridPane scene; @@ -160,6 +162,8 @@ public final class ChatScene implements Restorable { */ @FXML private void initialize() { + eventBus.registerListener(this); + // Initialize message and user rendering messageList.setCellFactory(MessageListCell::new); chatList.setCellFactory(new ListCellFactory<>(ChatControl::new)); @@ -201,110 +205,119 @@ public final class ChatScene implements Restorable { updateInfoLabel("You are offline", "info-label-warning"); } }); + } - // Listen to backEvents - eventBus.register(BackEvent.class, e -> tabPane.getSelectionModel().select(Tabs.CONTACT_LIST.ordinal())); + @Event(eventType = BackEvent.class) + private void onBackEvent() { tabPane.getSelectionModel().select(Tabs.CONTACT_LIST.ordinal()); } - // Listen to received messages - eventBus.register(MessageCreationEvent.class, e -> { - final var message = e.get(); + @Event + private void onMessageCreation(MessageCreationEvent evt) { + final var message = evt.get(); - // The sender of the message is the recipient of the chat - // Exceptions: this user is the sender (sync) or group message (group is - // recipient) - final var recipientID = message instanceof GroupMessage || message.getSenderID() == localDB.getUser().getID() ? message.getRecipientID() - : message.getSenderID(); - localDB.getChat(recipientID).ifPresent(chat -> { - chat.insert(message); - if (chat.equals(currentChat)) { - try { - currentChat.read(writeProxy); - } catch (final IOException e1) { - logger.log(Level.WARNING, "Could not read current chat: ", e1); - } - Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); }); - // TODO: Increment unread counter for group messages with status < RECEIVED - } else if (message.getSenderID() != localDB.getUser().getID() && message.getStatus() == RECEIVED) chat.incrementUnreadAmount(); + // The sender of the message is the recipient of the chat + // Exceptions: this user is the sender (sync) or group message (group is + // recipient) + final var recipientID = message instanceof GroupMessage || message.getSenderID() == localDB.getUser().getID() ? message.getRecipientID() + : message.getSenderID(); + localDB.getChat(recipientID).ifPresent(chat -> { + chat.insert(message); + if (chat.equals(currentChat)) { + try { + currentChat.read(writeProxy); + } catch (final IOException e1) { + logger.log(Level.WARNING, "Could not read current chat: ", e1); + } + Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); }); + // TODO: Increment unread counter for group messages with status < RECEIVED + } else + if (message.getSenderID() != localDB.getUser().getID() && message.getStatus() == MessageStatus.RECEIVED) chat.incrementUnreadAmount(); - // Move chat with most recent unread messages to the top - Platform.runLater(() -> { - chats.getSource().remove(chat); - ((ObservableList) chats.getSource()).add(0, chat); - - if (chat.equals(currentChat)) chatList.getSelectionModel().select(0); - }); - }); - }); - - // Listen to message status changes - eventBus.register(MessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(message -> { - message.setStatus(e.get()); - // Update UI if in current chat and the current user was the sender of the - // message - if (currentChat != null && message.getSenderID() == client.getSender().getID()) Platform.runLater(messageList::refresh); - })); - - eventBus.register(GroupMessageStatusChange.class, e -> localDB.getMessage(e.getID()).ifPresent(groupMessage -> { - ((GroupMessage) groupMessage).getMemberStatuses().replace(e.getMemberID(), e.get()); - - // Update UI if in current chat - if (currentChat != null && groupMessage.getRecipientID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh); - })); - - // Listen to user status changes - eventBus.register(UserStatusChange.class, - e -> chats.getSource() - .stream() - .filter(c -> c.getRecipient().getID() == e.getID()) - .findAny() - .map(Chat::getRecipient) - .ifPresent(u -> { ((User) u).setStatus(e.get()); Platform.runLater(() -> ListViewRefresh.deepRefresh(chatList)); })); - - // Listen to contacts changes - eventBus.register(ContactOperation.class, e -> { - final var contact = e.get(); - switch (e.getOperationType()) { - case ADD: - if (contact instanceof User) localDB.getUsers().put(contact.getName(), (User) contact); - final var chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact); - Platform.runLater(() -> ((ObservableList) chats.getSource()).add(0, chat)); - break; - case REMOVE: - Platform.runLater(() -> chats.getSource().removeIf(c -> c.getRecipient().equals(contact))); - break; - } - }); - - // Disable attachment button if server says attachments will be filtered out - eventBus.register(NoAttachments.class, e -> { + // Move chat with most recent unread messages to the top Platform.runLater(() -> { - attachmentButton.setDisable(true); - voiceButton.setDisable(true); - final var alert = new Alert(AlertType.ERROR); - alert.setTitle("No attachments possible"); - alert.setHeaderText("Your current server does not support attachments."); - alert.setContentText("If this is unplanned, please contact your server administrator."); - alert.showAndWait(); + chats.getSource().remove(chat); + ((ObservableList) chats.getSource()).add(0, chat); + + if (chat.equals(currentChat)) chatList.getSelectionModel().select(0); }); }); + } - eventBus.register(GroupCreationResult.class, e -> Platform.runLater(() -> { newGroupButton.setDisable(!e.get()); })); - - eventBus.register(ThemeChangeEvent.class, e -> { - settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE))); - voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE))); - attachmentButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("attachment", DEFAULT_ICON_SIZE))); - DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20); - attachmentView.setImage(isCustomAttachmentImage ? attachmentView.getImage() : DEFAULT_ATTACHMENT_VIEW_IMAGE); - messageSearchButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("search", DEFAULT_ICON_SIZE))); - clientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); - chatList.setCellFactory(new ListCellFactory<>(ChatControl::new)); - messageList.setCellFactory(MessageListCell::new); - if (currentChat.getRecipient() instanceof User) recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); - else recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43)); + @Event + private void onMessageStatusChange(MessageStatusChange evt) { + localDB.getMessage(evt.getID()).ifPresent(message -> { + message.setStatus(evt.get()); + // Update UI if in current chat and the current user was the sender of the + // message + if (currentChat != null && message.getSenderID() == client.getSender().getID()) Platform.runLater(messageList::refresh); }); } + @Event + private void onGroupMessageStatusChange(GroupMessageStatusChange evt) { + localDB.getMessage(evt.getID()).ifPresent(groupMessage -> { + ((GroupMessage) groupMessage).getMemberStatuses().replace(evt.getMemberID(), evt.get()); + + // Update UI if in current chat + if (currentChat != null && groupMessage.getRecipientID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh); + }); + } + + @Event + private void onUserStatusChange(UserStatusChange evt) { + chats.getSource() + .stream() + .filter(c -> c.getRecipient().getID() == evt.getID()) + .findAny() + .map(Chat::getRecipient) + .ifPresent(u -> { ((User) u).setStatus(evt.get()); Platform.runLater(() -> ListViewRefresh.deepRefresh(chatList)); }); + } + + @Event + private void onContactOperation(ContactOperation operation) { + final var contact = operation.get(); + switch (operation.getOperationType()) { + case ADD: + if (contact instanceof User) localDB.getUsers().put(contact.getName(), (User) contact); + final var chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact); + Platform.runLater(() -> ((ObservableList) chats.getSource()).add(0, chat)); + break; + case REMOVE: + Platform.runLater(() -> chats.getSource().removeIf(c -> c.getRecipient().equals(contact))); + break; + } + } + + @Event(eventType = NoAttachments.class) + private void onNoAttachments() { + Platform.runLater(() -> { + attachmentButton.setDisable(true); + voiceButton.setDisable(true); + final var alert = new Alert(AlertType.ERROR); + alert.setTitle("No attachments possible"); + alert.setHeaderText("Your current server does not support attachments."); + alert.setContentText("If this is unplanned, please contact your server administrator."); + alert.showAndWait(); + }); + } + + @Event + private void onGroupCreationResult(GroupCreationResult result) { Platform.runLater(() -> newGroupButton.setDisable(!result.get())); } + + @Event(eventType = ThemeChangeEvent.class) + private void onThemeChange() { + settingsButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("settings", DEFAULT_ICON_SIZE))); + voiceButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("microphone", DEFAULT_ICON_SIZE))); + attachmentButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("attachment", DEFAULT_ICON_SIZE))); + DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20); + attachmentView.setImage(isCustomAttachmentImage ? attachmentView.getImage() : DEFAULT_ATTACHMENT_VIEW_IMAGE); + messageSearchButton.setGraphic(new ImageView(IconUtil.loadIconThemeSensitive("search", DEFAULT_ICON_SIZE))); + clientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); + chatList.setCellFactory(new ListCellFactory<>(ChatControl::new)); + messageList.setCellFactory(MessageListCell::new); + if (currentChat.getRecipient() instanceof User) recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43)); + else recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43)); + } + /** * Initializes all {@code SystemCommands} used in {@code ChatScene}. * diff --git a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java index 1109e18..7dcefd8 100644 --- a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java +++ b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java @@ -1,26 +1,21 @@ package envoy.client.ui.controller; -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.logging.*; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.control.Alert.AlertType; -import envoy.client.event.BackEvent; -import envoy.client.event.SendEvent; -import envoy.client.ui.listcell.ContactControl; -import envoy.client.ui.listcell.ListCellFactory; +import envoy.client.event.*; +import envoy.client.ui.listcell.*; import envoy.data.User; import envoy.event.ElementOperation; -import envoy.event.EventBus; -import envoy.event.contact.ContactOperation; -import envoy.event.contact.UserSearchRequest; -import envoy.event.contact.UserSearchResult; +import envoy.event.contact.*; import envoy.util.EnvoyLog; +import dev.kske.eventbus.*; + /** * Provides a search bar in which a user name (substring) can be entered. The * users with a matching name are then displayed inside a list view. A @@ -39,7 +34,7 @@ import envoy.util.EnvoyLog; * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ -public class ContactSearchTab { +public class ContactSearchTab implements EventListener { @FXML private TextArea searchBar; @@ -48,26 +43,29 @@ public class ContactSearchTab { private ListView userList; private Alert alert = new Alert(AlertType.CONFIRMATION); - private User currentlySelectedUser; - private final Consumer handler = e -> { - final var contact = e.get(); - if (e.getOperationType() == ElementOperation.ADD) Platform.runLater(() -> { - userList.getItems().remove(contact); - if (currentlySelectedUser != null && currentlySelectedUser.equals(contact) && alert.isShowing()) alert.close(); - }); - }; - private static final EventBus eventBus = EventBus.getInstance(); private static final Logger logger = EnvoyLog.getLogger(ChatScene.class); @FXML private void initialize() { + eventBus.registerListener(this); userList.setCellFactory(new ListCellFactory<>(ContactControl::new)); - eventBus.register(UserSearchResult.class, - response -> Platform.runLater(() -> { userList.getItems().clear(); userList.getItems().addAll(response.get()); })); - eventBus.register(ContactOperation.class, handler); + } + + @Event + private void onUserSearchResult(UserSearchResult result) { + Platform.runLater(() -> { userList.getItems().clear(); userList.getItems().addAll(result.get()); }); + } + + @Event + private void onContactOperation(ContactOperation operation) { + final var contact = operation.get(); + if (operation.getOperationType() == ElementOperation.ADD) Platform.runLater(() -> { + userList.getItems().remove(contact); + if (currentlySelectedUser != null && currentlySelectedUser.equals(contact) && alert.isShowing()) alert.close(); + }); } /** diff --git a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java index 6c095d6..5e8d445 100644 --- a/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java +++ b/client/src/main/java/envoy/client/ui/controller/GroupCreationTab.java @@ -8,20 +8,15 @@ import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.layout.HBox; -import envoy.client.data.Chat; -import envoy.client.data.Context; -import envoy.client.data.LocalDB; -import envoy.client.event.BackEvent; -import envoy.client.event.SendEvent; -import envoy.client.ui.listcell.ContactControl; -import envoy.client.ui.listcell.ListCellFactory; -import envoy.data.Contact; -import envoy.data.Group; -import envoy.data.User; -import envoy.event.EventBus; +import envoy.client.data.*; +import envoy.client.event.*; +import envoy.client.ui.listcell.*; +import envoy.data.*; import envoy.event.GroupCreation; import envoy.util.Bounds; +import dev.kske.eventbus.*; + /** * Provides a group creation interface. A group name can be entered in the text * field at the top. Available users (local chat recipients) are displayed @@ -38,7 +33,7 @@ import envoy.util.Bounds; * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ -public class GroupCreationTab { +public class GroupCreationTab implements EventListener { @FXML private Button createButton; diff --git a/client/src/main/java/envoy/client/ui/controller/LoginScene.java b/client/src/main/java/envoy/client/ui/controller/LoginScene.java index 6d3f4ee..506170e 100644 --- a/client/src/main/java/envoy/client/ui/controller/LoginScene.java +++ b/client/src/main/java/envoy/client/ui/controller/LoginScene.java @@ -1,9 +1,7 @@ package envoy.client.ui.controller; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.logging.*; -import javafx.application.Platform; import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.scene.control.*; @@ -11,13 +9,12 @@ import javafx.scene.control.Alert.AlertType; import javafx.scene.image.ImageView; import envoy.client.data.ClientConfig; -import envoy.client.ui.IconUtil; -import envoy.client.ui.Startup; +import envoy.client.ui.*; import envoy.data.LoginCredentials; -import envoy.event.EventBus; import envoy.event.HandshakeRejection; -import envoy.util.Bounds; -import envoy.util.EnvoyLog; +import envoy.util.*; + +import dev.kske.eventbus.*; /** * Project: envoy-client
@@ -28,7 +25,7 @@ import envoy.util.EnvoyLog; * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ -public final class LoginScene { +public final class LoginScene implements EventListener { @FXML private TextField userTextField; @@ -60,7 +57,6 @@ public final class LoginScene { private boolean registration = false; private static final Logger logger = EnvoyLog.getLogger(LoginScene.class); - private static final EventBus eventBus = EventBus.getInstance(); private static final ClientConfig config = ClientConfig.getInstance(); @FXML @@ -68,7 +64,7 @@ public final class LoginScene { connectionLabel.setText("Server: " + config.getServer() + ":" + config.getPort()); // Show an alert after an unsuccessful handshake - eventBus.register(HandshakeRejection.class, e -> Platform.runLater(() -> { new Alert(AlertType.ERROR, e.get()).showAndWait(); })); + EventBus.getInstance().registerListener(this); logo.setImage(IconUtil.loadIcon("envoy_logo")); @@ -119,4 +115,7 @@ public final class LoginScene { logger.log(Level.INFO, "The login process has been cancelled. Exiting..."); System.exit(0); } + + @Event + private void onHandshakeRejection(HandshakeRejection evt) { new Alert(AlertType.ERROR, evt.get()).showAndWait(); } } diff --git a/client/src/main/java/envoy/client/ui/settings/BugReportPane.java b/client/src/main/java/envoy/client/ui/settings/BugReportPane.java index 211d8d8..88b0397 100644 --- a/client/src/main/java/envoy/client/ui/settings/BugReportPane.java +++ b/client/src/main/java/envoy/client/ui/settings/BugReportPane.java @@ -7,9 +7,10 @@ import javafx.scene.input.InputEvent; import envoy.client.event.SendEvent; import envoy.client.util.IssueUtil; import envoy.data.User; -import envoy.event.EventBus; import envoy.event.IssueProposal; +import dev.kske.eventbus.EventBus; + /** * This class offers the option for users to submit a bug report. Only the title * of a bug is needed to be sent. diff --git a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java index bf48b5f..cb87294 100644 --- a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java @@ -1,12 +1,12 @@ package envoy.client.ui.settings; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Tooltip; +import javafx.scene.control.*; import envoy.client.data.SettingsItem; import envoy.client.event.ThemeChangeEvent; import envoy.data.User.UserStatus; -import envoy.event.EventBus; + +import dev.kske.eventbus.EventBus; /** * Project: envoy-client
@@ -44,7 +44,7 @@ public final class GeneralSettingsPane extends SettingsPane { combobox.setTooltip(new Tooltip("Determines the current theme Envoy will be displayed in.")); combobox.setValue(settings.getCurrentTheme()); combobox.setOnAction( - e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent(combobox.getValue())); }); + e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); }); getChildren().add(combobox); final var statusComboBox = new ComboBox(); diff --git a/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java index d752c43..498a940 100644 --- a/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/UserSettingsPane.java @@ -1,31 +1,27 @@ package envoy.client.ui.settings; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.logging.*; import javafx.event.EventHandler; import javafx.geometry.Pos; import javafx.scene.Cursor; import javafx.scene.control.*; import javafx.scene.control.Alert.AlertType; -import javafx.scene.image.Image; -import javafx.scene.image.ImageView; +import javafx.scene.image.*; import javafx.scene.input.InputEvent; import javafx.scene.layout.HBox; import javafx.stage.FileChooser; import envoy.client.event.SendEvent; -import envoy.client.ui.IconUtil; -import envoy.client.ui.SceneContext; +import envoy.client.ui.*; import envoy.client.ui.custom.ProfilePicImageView; import envoy.data.User; import envoy.event.*; -import envoy.util.Bounds; -import envoy.util.EnvoyLog; +import envoy.util.*; + +import dev.kske.eventbus.EventBus; /** * Project: envoy-client
diff --git a/client/src/main/java/module-info.java b/client/src/main/java/module-info.java index 778f673..bfcf8d2 100644 --- a/client/src/main/java/module-info.java +++ b/client/src/main/java/module-info.java @@ -7,19 +7,20 @@ * @author Maximilian Käfer * @since Envoy Client v0.1-beta */ -module envoy { +module envoy.client { - requires transitive envoy.common; - requires transitive java.desktop; - requires transitive java.logging; - requires transitive java.prefs; + requires envoy.common; + requires java.desktop; + requires java.logging; + requires java.prefs; requires javafx.controls; requires javafx.fxml; requires javafx.base; requires javafx.graphics; - opens envoy.client.ui to javafx.graphics, javafx.fxml; - opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util; + opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus; + opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus; opens envoy.client.ui.custom to javafx.graphics, javafx.fxml; opens envoy.client.ui.settings to envoy.client.util; + opens envoy.client.net to dev.kske.eventbus; } diff --git a/common/pom.xml b/common/pom.xml index 190ddec..b2165ef 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -12,11 +12,24 @@ 0.1-beta + + + kske-repo + https://kske.dev/maven-repo + + + + + dev.kske + event-bus + 0.0.3 + org.junit.jupiter junit-jupiter-engine 5.5.2 + test diff --git a/common/src/main/java/envoy/event/Event.java b/common/src/main/java/envoy/event/Event.java index 809c5ec..33ccc24 100644 --- a/common/src/main/java/envoy/event/Event.java +++ b/common/src/main/java/envoy/event/Event.java @@ -2,7 +2,13 @@ package envoy.event; import java.io.Serializable; +import dev.kske.eventbus.IEvent; + /** + * This class serves as a convenience base class for all events. It implements + * the {@link IEvent} interface and provides a generic value. For events without + * a value there also is {@link envoy.event.Event.Valueless}. + *

* Project: envoy-common
* File: Event.java
* Created: 04.12.2019
@@ -11,7 +17,7 @@ import java.io.Serializable; * @param the type of the Event * @since Envoy v0.2-alpha */ -public abstract class Event implements Serializable { +public abstract class Event implements IEvent, Serializable { protected final T value; diff --git a/common/src/main/java/envoy/event/EventBus.java b/common/src/main/java/envoy/event/EventBus.java deleted file mode 100644 index 51fb963..0000000 --- a/common/src/main/java/envoy/event/EventBus.java +++ /dev/null @@ -1,82 +0,0 @@ -package envoy.event; - -import java.util.*; -import java.util.function.Consumer; - -/** - * This class handles events by allowing event handlers to register themselves - * and then be notified about certain events dispatched by the event bus.
- *
- * The event bus is a singleton and can be used across the entire application to - * guarantee the propagation of events.
- *
- * Project: envoy-common
- * File: EventBus.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public final class EventBus { - - /** - * Contains all event handler instances registered at this event bus as values - * mapped to by their supported event classes. - */ - private Map>, List>>> handlers = new HashMap<>(); - - /** - * The singleton instance of this event bus that is used across the - * entire application. - */ - private static EventBus eventBus = new EventBus(); - - /** - * This constructor is not accessible from outside this class because a - * singleton instance of it is provided by the {@link EventBus#getInstance()} - * method. - */ - private EventBus() {} - - /** - * @return the singleton instance of the event bus - * @since Envoy v0.2-alpha - */ - public static EventBus getInstance() { return eventBus; } - - /** - * Registers an event handler to be notified when an - * event of a certain type is dispatched. - * - * @param the type of event values to notify the handler about - * @param eventClass the class which the event handler is subscribing to - * @param handler the event handler to register - * @since Envoy v0.2-alpha - */ - public > void register(Class eventClass, Consumer handler) { - if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>()); - handlers.get(eventClass).add((Consumer>) handler); - } - - /** - * Dispatches an event to every event handler subscribed to it. - * - * @param event the {@link Event} to dispatch - * @since Envoy v0.2-alpha - */ - public void dispatch(Event event) { - handlers.keySet() - .stream() - .filter(event.getClass()::equals) - .map(handlers::get) - .flatMap(List::stream) - .forEach(h -> h.accept(event)); - } - - /** - * @return a map of all event handler instances currently registered at this - * event bus with the event classes they are subscribed to as keys - * @since Envoy v0.2-alpha - */ - public Map>, List>>> getHandlers() { return handlers; } -} diff --git a/common/src/main/java/module-info.java b/common/src/main/java/module-info.java index e4aa197..3e6a4b5 100644 --- a/common/src/main/java/module-info.java +++ b/common/src/main/java/module-info.java @@ -16,4 +16,5 @@ module envoy.common { exports envoy.event.contact; requires transitive java.logging; + requires transitive dev.kske.eventbus; } diff --git a/server/src/main/java/module-info.java b/server/src/main/java/module-info.java index 860f1df..7707142 100755 --- a/server/src/main/java/module-info.java +++ b/server/src/main/java/module-info.java @@ -16,5 +16,4 @@ module envoy.server { requires transitive java.persistence; requires transitive java.sql; requires transitive org.hibernate.orm.core; - } -- 2.30.2