From 4067be6bc2f99ab3b8d781dc0b36a9e94813e16d Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sat, 28 Dec 2019 22:20:43 +0200 Subject: [PATCH 01/10] Started integration of new server architecture * Removed JAX-RS dependency from POM * Changed version in POM to 0.3-alpha The errors that appear throughout LocalDB and Client are caused by the architecture change and will be removed in future commits. --- pom.xml | 14 +----- src/main/java/envoy/client/Chat.java | 4 +- src/main/java/envoy/client/Client.java | 5 +- src/main/java/envoy/client/LocalDB.java | 46 ++++--------------- .../client/event/MessageCreationEvent.java | 2 +- .../java/envoy/client/event/MessageEvent.java | 2 +- .../event/MessageModificationEvent.java | 2 +- src/main/java/envoy/client/ui/ChatWindow.java | 15 +++--- .../envoy/client/ui/MessageListRenderer.java | 20 ++++---- src/main/java/envoy/client/ui/Startup.java | 4 +- .../java/envoy/client/ui/StatusTrayIcon.java | 24 +++++----- .../envoy/client/ui/UserListRenderer.java | 4 +- 12 files changed, 51 insertions(+), 91 deletions(-) diff --git a/pom.xml b/pom.xml index d688c37..28e6f60 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ informatik-ag-ngl envoy-client - 0.0.1-SNAPSHOT + 0.3-alpha Envoy Client https://github.com/informatik-ag-ngl/envoy-client @@ -18,20 +18,10 @@ - - org.jboss.resteasy - resteasy-client - 4.1.1.Final - - - org.jboss.resteasy - resteasy-jaxb-provider - 4.3.1.Final - informatik-ag-ngl envoy-common - 0.0.1-SNAPSHOT + 0.2-alpha diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index daca33a..ef762c4 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -4,8 +4,8 @@ import java.io.Serializable; import javax.swing.DefaultListModel; -import envoy.schema.Message; -import envoy.schema.User; +import envoy.data.Message; +import envoy.data.User; /** * Represents a chat between two {@link User}s
diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index edc4839..1d27d5b 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -14,10 +14,8 @@ import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import envoy.client.util.EnvoyLog; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.ObjectFactory; -import envoy.schema.Sync; -import envoy.schema.User; /** * Project: envoy-client
@@ -31,7 +29,6 @@ import envoy.schema.User; */ public class Client { - private ObjectFactory objectFactory = new ObjectFactory(); private Config config; private User sender, recipient; private boolean online = false; diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index b5e3971..c86e3a0 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -2,10 +2,10 @@ package envoy.client; import java.io.File; import java.io.IOException; -import java.time.Instant; import java.util.*; import java.util.logging.Logger; +import javax.naming.spi.ObjectFactory; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; @@ -13,9 +13,9 @@ import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; import envoy.client.util.SerializationUtils; +import envoy.data.Message; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.*; -import envoy.schema.Message.Metadata.MessageState; /** * Project: envoy-client
@@ -73,7 +73,7 @@ public class LocalDB { */ public void initializeDBFile() { if (user == null) throw new NullPointerException("Client user is null"); - localDBFile = new File(localDBDir, user.getID() + ".db"); + localDBFile = new File(localDBDir, user.getId() + ".db"); } /** @@ -107,32 +107,6 @@ public class LocalDB { */ public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - /** - * Creates a {@link Message} object serializable to XML. - * - * @param textContent The content (text) of the message - * @param recipientID The recipient of the message - * @return prepared {@link Message} object - * @since Envoy v0.1-alpha - */ - public Message createMessage(String textContent, long recipientID) { - Message.Metadata metaData = objectFactory.createMessageMetadata(); - metaData.setSender(user.getID()); - metaData.setRecipient(recipientID); - metaData.setState(MessageState.WAITING); - metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString())); - - Message.Content content = objectFactory.createMessageContent(); - content.setType("text"); - content.setText(textContent); - - Message message = objectFactory.createMessage(); - message.setMetadata(metaData); - message.getContent().add(content); - - return message; - } - /** * Creates a {@link Sync} object filled with the changes that occurred to the * local database since the last synchronization. @@ -181,7 +155,7 @@ public class LocalDB { } else { // Update Messages in localDB to state RECEIVED for (Chat chat : getChats()) - if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) + if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) for (int j = 0; j < chat.getModel().getSize(); j++) if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() .get(i) @@ -195,8 +169,8 @@ public class LocalDB { logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + "was initialized to be set to READ in localDB."); for (Chat chat : getChats()) - if (chat.getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + chat.getRecipient().getID() + "was selected."); + if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); for (int k = 0; k < chat.getModel().getSize(); k++) if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() .get(i) @@ -215,7 +189,7 @@ public class LocalDB { // Updating UserStatus of all users in LocalDB for (User user : returnSync.getUsers()) for (Chat chat : getChats()) - if (user.getID() == chat.getRecipient().getID()) chat.getRecipient().setStatus(user.getStatus()); + if (user.getId() == chat.getRecipient().getId()) chat.getRecipient().setStatus(user.getStatus()); sync.getMessages().clear(); sync.getUsers().clear(); @@ -230,7 +204,7 @@ public class LocalDB { public void addUnreadMessagesToLocalDB() { for (Message message : unreadMessagesSync.getMessages()) for (Chat chat : getChats()) - if (message.getMetadata().getSender() == chat.getRecipient().getID()) { + if (message.getMetadata().getSender() == chat.getRecipient().getId()) { chat.appendMessage(message); break; } @@ -247,7 +221,7 @@ public class LocalDB { */ public void setMessagesToRead(Chat currentChat) { for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID()) + if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getId()) if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); readMessages.getMessages().add(currentChat.getModel().get(i)); diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 28f1b58..36397d9 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java index 2e818e5..1dab6e7 100644 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ b/src/main/java/envoy/client/event/MessageEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 0b83ef0..248c6f1 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,6 +1,6 @@ package envoy.client.event; -import envoy.schema.Message; +import envoy.data.Message; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dc68e10..5f8ff21 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -14,8 +14,9 @@ import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; -import envoy.schema.Message; -import envoy.schema.User; +import envoy.data.Message; +import envoy.data.TextMessage; +import envoy.data.User; /** * Project: envoy-client
@@ -164,7 +165,7 @@ public class ChatWindow extends JFrame { final JList selectedUserList = (JList) listSelectionEvent.getSource(); final User user = selectedUserList.getSelectedValue(); - currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); // Set all unread messages in the chat to read readCurrentChat(); @@ -246,7 +247,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient().getID()); + final Message message = new TextMessage(0, localDB.getUser(), currentChat.getRecipient(), messageEnterTextArea.getText()); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); @@ -275,7 +276,7 @@ public class ChatWindow extends JFrame { userListModel.addElement(user); // Check if user exists in local DB - if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + if (localDB.getChats().stream().filter(c -> c.getRecipient().getId() == user.getId()).count() == 0) localDB.getChats().add(new Chat(user)); }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); @@ -296,7 +297,7 @@ public class ChatWindow extends JFrame { // Synchronize try { - localDB.applySync(client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.applySync(client.sendSync(client.getSender().getId(), localDB.fillSync(client.getSender().getId()))); } catch (Exception e) { logger.log(Level.SEVERE, "Could not perform sync", e); } @@ -317,7 +318,7 @@ public class ChatWindow extends JFrame { private void updateUserStates() { for (int i = 0; i < userList.getModel().getSize(); i++) for (int j = 0; j < localDB.getChats().size(); j++) - if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID()) + if (userList.getModel().getElementAt(i).getId() == localDB.getChats().get(j).getRecipient().getId()) userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); } diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index ddd2230..967b1cc 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -8,7 +8,8 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.client.Settings; -import envoy.schema.Message; +import envoy.data.Message; +import envoy.data.TextMessage; /** * Defines how a message is displayed.
@@ -37,19 +38,18 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s :%s", dateColor, diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 8e57a08..1125030 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -12,8 +12,8 @@ import javax.swing.SwingUtilities; import envoy.client.*; import envoy.client.util.EnvoyLog; +import envoy.data.User; import envoy.exception.EnvoyException; -import envoy.schema.User; /** * Starts the Envoy client and prompts the user to enter their name.
@@ -129,7 +129,7 @@ public class Startup { JOptionPane.WARNING_MESSAGE); } - logger.info("Client user ID: " + client.getSender().getID()); + logger.info("Client user ID: " + client.getSender().getId()); // Save all users to the local database if (client.isOnline()) localDB.setUsers(client.getUsers()); diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 4670377..68427f6 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -1,21 +1,15 @@ package envoy.client.ui; -import java.awt.AWTException; -import java.awt.Image; -import java.awt.MenuItem; -import java.awt.PopupMenu; -import java.awt.SystemTray; -import java.awt.Toolkit; -import java.awt.TrayIcon; +import java.awt.*; import java.awt.TrayIcon.MessageType; -import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; +import envoy.data.Message; +import envoy.data.TextMessage; import envoy.exception.EnvoyException; -import envoy.schema.Message; /** * Project: envoy-client
@@ -81,10 +75,14 @@ public class StatusTrayIcon { trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); }); // Start processing message events - EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { - if (displayMessages) - trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getContent().get(0).getText(), MessageType.INFO); - }); + EventBus.getInstance() + .register(MessageCreationEvent.class, + (evt) -> { + // TODO: Handle other message types + if (displayMessages) trayIcon.displayMessage("New message received", + ((TextMessage) ((MessageCreationEvent) evt).get()).getContent(), + MessageType.INFO); + }); } /** diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index ca7214d..9441801 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -7,8 +7,8 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.client.Settings; -import envoy.schema.User; -import envoy.schema.User.UserStatus; +import envoy.data.User; +import envoy.data.User.UserStatus; /** * Defines how the {@code UserList} is displayed.
From 0efc8dbbc7a566cd0864a2c79a386d65aa51c541 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Sun, 29 Dec 2019 12:54:05 +0200 Subject: [PATCH 02/10] Working on handshake mechanism with login --- src/main/java/envoy/client/Client.java | 170 ++------- src/main/java/envoy/client/LocalDB.java | 338 +++++++++--------- src/main/java/envoy/client/Settings.java | 10 +- src/main/java/envoy/client/event/Event.java | 19 - .../java/envoy/client/event/EventBus.java | 81 ----- .../java/envoy/client/event/EventHandler.java | 18 - .../client/event/MessageCreationEvent.java | 1 + .../java/envoy/client/event/MessageEvent.java | 27 -- .../event/MessageModificationEvent.java | 1 + .../envoy/client/event/ThemeChangeEvent.java | 1 + src/main/java/envoy/client/ui/ChatWindow.java | 17 +- src/main/java/envoy/client/ui/Startup.java | 12 +- .../java/envoy/client/ui/StatusTrayIcon.java | 2 +- .../client/ui/settings/SettingsScreen.java | 2 +- .../ui/settings/ThemeCustomizationPanel.java | 2 +- .../envoy/client/util/SerializationUtils.java | 57 --- 16 files changed, 230 insertions(+), 528 deletions(-) delete mode 100644 src/main/java/envoy/client/event/Event.java delete mode 100644 src/main/java/envoy/client/event/EventBus.java delete mode 100644 src/main/java/envoy/client/event/EventHandler.java delete mode 100644 src/main/java/envoy/client/event/MessageEvent.java delete mode 100644 src/main/java/envoy/client/util/SerializationUtils.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 1d27d5b..6a4b754 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,21 +1,15 @@ package envoy.client; -import java.io.StringWriter; -import java.util.HashMap; +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; import java.util.Map; import java.util.logging.Logger; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Response; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; - import envoy.client.util.EnvoyLog; +import envoy.data.LoginCredentials; import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Project: envoy-client
@@ -29,43 +23,41 @@ import envoy.exception.EnvoyException; */ public class Client { - private Config config; - private User sender, recipient; - private boolean online = false; + private Socket socket; + private Config config = Config.getInstance(); + private User sender, recipient; + private boolean online; private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); - /** - * Initializes the client. At this state, the client user has yet to be - * initialized, which can be done by calling {@link Client#onlineInit(String)}. - * - * @param config The {@link Config} instance to use in this client - * @since Envoy v0.2-alpha - */ - public Client(Config config) { this.config = config; } - /** * Enters the online mode by acquiring a user ID from the server. * - * @param userName the name of the client user - * @throws EnvoyException if the online mode could not be entered or the request - * failed for some other reason + * @param credentials the login credentials of the user + * @throws IOException if the online mode could not be entered or the request + * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(String userName) throws EnvoyException { - sender = getUser(userName); - online = true; - } + public void onlineInit(LoginCredentials credentials) throws IOException { + logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); + socket = new Socket(config.getServer(), config.getPort()); + logger.info("Successfully connected to server."); - private R post(String uri, T body, Class responseBodyClass) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(uri); - Response response = target.request().post(Entity.entity(body, "application/xml")); - R responseBody = response.readEntity(responseBodyClass); - response.close(); - client.close(); + // Write login credentials + logger.finest("Sending login credentials..."); + SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - return responseBody; + // Read response (user object) + InputStream in = socket.getInputStream(); + + // Read object + try { + sender = SerializationUtils.read(in, User.class); + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + + online = true; } /** @@ -74,106 +66,8 @@ public class Client { * @since Envoy v0.2-alpha */ public Map getUsers() { - Sync sendSync = objectFactory.createSync(); - User user = objectFactory.createUser(); - user.setID(-1); - sendSync.getUsers().add(user); - - Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), - sendSync, - Sync.class); - - Map users = new HashMap<>(); - returnSync.getUsers().forEach(u -> users.put(u.getName(), u)); - return users; - } - - /** - * Returns a {@link User} with a specific id by name. - * - * @param name - the name of the {@link User} - * @return a {@link User} with the specified name - * @throws EnvoyException if the server does not return the requested ID - * @since Envoy v0.1-alpha - */ - private User getUser(String name) throws EnvoyException { - // Create a sync with only a user with the requested name - Sync senderSync = objectFactory.createSync(); - User user = objectFactory.createUser(); - user.setName(name); - senderSync.getUsers().add(user); - - try { - Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), - senderSync, - Sync.class); - - // Expecting a single user with an ID - if (sync.getUsers().size() == 1) { - online = true; - return sync.getUsers().get(0); - } else throw new EnvoyException("Unexpected response from Envoy Server"); - } catch (Exception e) { - throw new EnvoyException("Could not connect to server", e); - } - } - - /** - * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync - * Object as response.
- * It is also used to get the own sender at the start of the client - * (Client sends "sync" Sync Object with single user in it(name: the name - * entered at login, id: 0, UserStatus:null))
- * and to get a complete list of all users saved on the server. - * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: - * -1, UserStatus:null))
- * This method also processes the response Sync Object.
- * It sorts its users and messages by specific variables and does certain things - * with them.
- *
- * Messages:
- * -State SENT: Update Local message(s) with State WAITING (add Message ID and - * change State to SENT). (server sends these informations to the client if - * message(s) with State WAITING were successfully sent to the server)
- * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the - * server in the latest sync to the "unreadMessagesSync" Sync Object.
- * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state - * RECEIVED. - * (server sends these informations to the client if the other client received - * the message(s).)
- * -State READ: Update message(s) in the LocalDB to state READ. (server sends - * these informations to the client if the other client read - * the message(s).)
- *
- * Users:
- * Updating UserStatus of all users in LocalDB. (Server sends all users with - * their updated UserStatus to the client.)
- * - * @param userId the id of the {@link Client} who sends the {@link Sync} - * @param sync the sync object (yet to be converted from java class to - * sync.xml) - * @return a returnSync.xml file - * @throws EnvoyException if the client is not in online mode - * @since Envoy v0.1-alpha - */ - public Sync sendSync(long userId, Sync sync) throws EnvoyException { - if(!isOnline()) - throw new EnvoyException("Client is not in online mode"); - // Print sync XML to console - JAXBContext jc; - try { - jc = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - StringWriter stringWriter = new StringWriter(); - m.marshal(sync, stringWriter); - logger.fine("Sending sync:\n" + stringWriter.toString()); - } catch (JAXBException e) { - e.printStackTrace(); - } - - // Send sync - return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); + // TODO + return null; } /** diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index c86e3a0..d550c3a 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -5,17 +5,9 @@ import java.io.IOException; import java.util.*; import java.util.logging.Logger; -import javax.naming.spi.ObjectFactory; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; - -import envoy.client.event.EventBus; -import envoy.client.event.MessageCreationEvent; import envoy.client.util.EnvoyLog; -import envoy.client.util.SerializationUtils; -import envoy.data.Message; import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Project: envoy-client
@@ -33,13 +25,6 @@ public class LocalDB { private Map users = new HashMap<>(); private List chats = new ArrayList<>(); - private ObjectFactory objectFactory = new ObjectFactory(); - private DatatypeFactory datatypeFactory; - - private Sync unreadMessagesSync = objectFactory.createSync(); - private Sync sync = objectFactory.createSync(); - private Sync readMessages = objectFactory.createSync(); - private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); /** @@ -53,12 +38,6 @@ public class LocalDB { public LocalDB(File localDBDir) throws IOException { this.localDBDir = localDBDir; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } - // Initialize local database directory if (localDBDir.exists() && !localDBDir.isDirectory()) throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); @@ -93,162 +72,181 @@ public class LocalDB { /** * Loads all users that are stored in the local database. - * - * @throws EnvoyException if the loading process failed + * + * @throws IOException if the loading process failed + * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.2-alpha */ - public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); } + public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } /** * Loads all chats saved by Envoy for the client user. - * - * @throws EnvoyException if the loading process failed + * + * @throws IOException if the loading process failed + * @throws ClassNotFoundException if the loading process failed * @since Envoy v0.1-alpha */ - public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } + public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - /** - * Creates a {@link Sync} object filled with the changes that occurred to the - * local database since the last synchronization. - * - * @param userId the ID of the user that is synchronized by this client - * @return {@link Sync} object filled with the current changes - * @since Envoy v0.1-alpha - */ - public Sync fillSync(long userId) { - addWaitingMessagesToSync(); - - sync.getMessages().addAll(readMessages.getMessages()); - readMessages.getMessages().clear(); - - logger.finest(String.format("Filled sync with %d messages.", sync.getMessages().size())); - return sync; - } - - /** - * Applies the changes carried by a {@link Sync} object to the local database - * - * @param returnSync the {@link Sync} object to apply - * @since Envoy v0.1-alpha - */ - public void applySync(Sync returnSync) { - for (int i = 0; i < returnSync.getMessages().size(); i++) { - - // The message has an ID - if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - - // Messages are processes differently corresponding to their state - switch (returnSync.getMessages().get(i).getMetadata().getState()) { - case SENT: - // Update previously waiting and now sent messages that were assigned an ID by - // the server - sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); - sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - break; - case RECEIVED: - if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { - // these are the unread Messages from the server - unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - - // Create and dispatch message creation event - EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); - } else { - // Update Messages in localDB to state RECEIVED - for (Chat chat : getChats()) - if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) - for (int j = 0; j < chat.getModel().getSize(); j++) - if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) - chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - } - break; - case READ: - // Update local Messages to state READ - logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() - + "was initialized to be set to READ in localDB."); - for (Chat chat : getChats()) - if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { - logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); - for (int k = 0; k < chat.getModel().getSize(); k++) - if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() - .get(i) - .getMetadata() - .getMessageId()) { - logger.info("Message with ID: " + chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); - chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - logger.info("Message State is now: " + chat.getModel().get(k).getMetadata().getState()); - } - } - break; - } - } - } - - // Updating UserStatus of all users in LocalDB - for (User user : returnSync.getUsers()) - for (Chat chat : getChats()) - if (user.getId() == chat.getRecipient().getId()) chat.getRecipient().setStatus(user.getStatus()); - - sync.getMessages().clear(); - sync.getUsers().clear(); - } - - /** - * Adds the unread messages returned from the server in the latest sync to the - * right chats in the LocalDB. - * - * @since Envoy v0.1-alpha - */ - public void addUnreadMessagesToLocalDB() { - for (Message message : unreadMessagesSync.getMessages()) - for (Chat chat : getChats()) - if (message.getMetadata().getSender() == chat.getRecipient().getId()) { - chat.appendMessage(message); - break; - } - } - - /** - * Changes all messages with state {@code RECEIVED} of a specific chat to state - * {@code READ}. - *
- * Adds these messages to the {@code readMessages} {@link Sync} object. - * - * @param currentChat the {@link Chat} that was just opened - * @since Envoy v0.1-alpha - */ - public void setMessagesToRead(Chat currentChat) { - for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getId()) - if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) { - currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); - readMessages.getMessages().add(currentChat.getModel().get(i)); - } else break; - } - - /** - * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the - * {@link Sync} object. - * - * @since Envoy v0.1-alpha - */ - private void addWaitingMessagesToSync() { - for (Chat chat : getChats()) - for (int i = 0; i < chat.getModel().size(); i++) - if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) { - logger.info("Got Waiting Message"); - sync.getMessages().add(chat.getModel().get(i)); - } - } - - /** - * Clears the {@code unreadMessagesSync} {@link Sync} object. - * - * @since Envoy v0.1-alpha - */ - public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + // /** + // * Creates a {@link Sync} object filled with the changes that occurred to the + // * local database since the last synchronization. + // * + // * @param userId the ID of the user that is synchronized by this client + // * @return {@link Sync} object filled with the current changes + // * @since Envoy v0.1-alpha + // */ + // public Sync fillSync(long userId) { + // addWaitingMessagesToSync(); + // + // sync.getMessages().addAll(readMessages.getMessages()); + // readMessages.getMessages().clear(); + // + // logger.finest(String.format("Filled sync with %d messages.", + // sync.getMessages().size())); + // return sync; + // } + // + // /** + // * Applies the changes carried by a {@link Sync} object to the local database + // * + // * @param returnSync the {@link Sync} object to apply + // * @since Envoy v0.1-alpha + // */ + // public void applySync(Sync returnSync) { + // for (int i = 0; i < returnSync.getMessages().size(); i++) { + // + // // The message has an ID + // if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { + // + // // Messages are processes differently corresponding to their state + // switch (returnSync.getMessages().get(i).getMetadata().getState()) { + // case SENT: + // // Update previously waiting and now sent messages that were assigned an ID + // by + // // the server + // sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); + // sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // break; + // case RECEIVED: + // if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { + // // these are the unread Messages from the server + // unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + // + // // Create and dispatch message creation event + // EventBus.getInstance().dispatch(new + // MessageCreationEvent(returnSync.getMessages().get(i))); + // } else { + // // Update Messages in localDB to state RECEIVED + // for (Chat chat : getChats()) + // if (chat.getRecipient().getId() == + // returnSync.getMessages().get(i).getMetadata().getRecipient()) + // for (int j = 0; j < chat.getModel().getSize(); j++) + // if (chat.getModel().get(j).getMetadata().getMessageId() == + // returnSync.getMessages() + // .get(i) + // .getMetadata() + // .getMessageId()) + // chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // } + // break; + // case READ: + // // Update local Messages to state READ + // logger.info("Message with ID: " + + // returnSync.getMessages().get(i).getMetadata().getMessageId() + // + "was initialized to be set to READ in localDB."); + // for (Chat chat : getChats()) + // if (chat.getRecipient().getId() == + // returnSync.getMessages().get(i).getMetadata().getRecipient()) { + // logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); + // for (int k = 0; k < chat.getModel().getSize(); k++) + // if (chat.getModel().get(k).getMetadata().getMessageId() == + // returnSync.getMessages() + // .get(i) + // .getMetadata() + // .getMessageId()) { + // logger.info("Message with ID: " + + // chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); + // chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); + // logger.info("Message State is now: " + + // chat.getModel().get(k).getMetadata().getState()); + // } + // } + // break; + // } + // } + // } + // + // // Updating UserStatus of all users in LocalDB + // for (User user : returnSync.getUsers()) + // for (Chat chat : getChats()) + // if (user.getId() == chat.getRecipient().getId()) + // chat.getRecipient().setStatus(user.getStatus()); + // + // sync.getMessages().clear(); + // sync.getUsers().clear(); + // } + // + // /** + // * Adds the unread messages returned from the server in the latest sync to the + // * right chats in the LocalDB. + // * + // * @since Envoy v0.1-alpha + // */ + // public void addUnreadMessagesToLocalDB() { + // for (Message message : unreadMessagesSync.getMessages()) + // for (Chat chat : getChats()) + // if (message.getMetadata().getSender() == chat.getRecipient().getId()) { + // chat.appendMessage(message); + // break; + // } + // } + // + // /** + // * Changes all messages with state {@code RECEIVED} of a specific chat to + // state + // * {@code READ}. + // *
+ // * Adds these messages to the {@code readMessages} {@link Sync} object. + // * + // * @param currentChat the {@link Chat} that was just opened + // * @since Envoy v0.1-alpha + // */ + // public void setMessagesToRead(Chat currentChat) { + // for (int i = currentChat.getModel().size() - 1; i >= 0; --i) + // if (currentChat.getModel().get(i).getMetadata().getRecipient() != + // currentChat.getRecipient().getId()) + // if (currentChat.getModel().get(i).getMetadata().getState() == + // MessageState.RECEIVED) { + // currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); + // readMessages.getMessages().add(currentChat.getModel().get(i)); + // } else break; + // } + // + // /** + // * Adds all messages with state {@code WAITING} from the {@link LocalDB} to + // the + // * {@link Sync} object. + // * + // * @since Envoy v0.1-alpha + // */ + // private void addWaitingMessagesToSync() { + // for (Chat chat : getChats()) + // for (int i = 0; i < chat.getModel().size(); i++) + // if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) + // { + // logger.info("Got Waiting Message"); + // sync.getMessages().add(chat.getModel().get(i)); + // } + // } + // + // /** + // * Clears the {@code unreadMessagesSync} {@link Sync} object. + // * + // * @since Envoy v0.1-alpha + // */ + // public void clearUnreadMessagesSync() { + // unreadMessagesSync.getMessages().clear(); } /** * @return a {@code Map} of all users stored locally with their diff --git a/src/main/java/envoy/client/Settings.java b/src/main/java/envoy/client/Settings.java index cdecc33..ef451d0 100644 --- a/src/main/java/envoy/client/Settings.java +++ b/src/main/java/envoy/client/Settings.java @@ -1,14 +1,14 @@ package envoy.client; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; import envoy.client.ui.Color; import envoy.client.ui.Theme; -import envoy.client.util.SerializationUtils; -import envoy.exception.EnvoyException; +import envoy.util.SerializationUtils; /** * Manages all application settings, which are different objects that can be @@ -55,7 +55,7 @@ public class Settings { // Load settings from settings file try { items = SerializationUtils.read(settingsFile, HashMap.class); - } catch (EnvoyException e) { + } catch (ClassNotFoundException | IOException e) { items = new HashMap<>(); } supplementDefaults(); @@ -63,7 +63,7 @@ public class Settings { // Load themes from theme file try { themes = SerializationUtils.read(themeFile, HashMap.class); - } catch (EnvoyException e1) { + } catch (ClassNotFoundException | IOException e1) { themes = new HashMap<>(); setCurrentTheme("dark"); } diff --git a/src/main/java/envoy/client/event/Event.java b/src/main/java/envoy/client/event/Event.java deleted file mode 100644 index 8e5393a..0000000 --- a/src/main/java/envoy/client/event/Event.java +++ /dev/null @@ -1,19 +0,0 @@ -package envoy.client.event; - -/** - * Project: envoy-client
- * File: Event.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @param the type of the Event - * @since Envoy v0.2-alpha - */ -public interface Event { - - /** - * @return the data associated with this event - */ - T get(); -} - diff --git a/src/main/java/envoy/client/event/EventBus.java b/src/main/java/envoy/client/event/EventBus.java deleted file mode 100644 index 06b385f..0000000 --- a/src/main/java/envoy/client/event/EventBus.java +++ /dev/null @@ -1,81 +0,0 @@ -package envoy.client.event; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class handles events by allowing {@link EventHandler} object 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-client
- * File: EventBus.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.2-alpha - */ -public class EventBus { - - /** - * Contains all {@link EventHandler} instances registered at this - * {@link EventBus} as values mapped to by their supported {@link Event} - * classes. - */ - private Map>, List> handlers = new HashMap<>(); - - /** - * The singleton instance of this {@link EventBus} 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 {@link EventBus} - * @since Envoy v0.2-alpha - */ - public static EventBus getInstance() { return eventBus; } - - /** - * Registers an {@link EventHandler} to be notified when a - * {@link Event} of a certain type is dispatched. - * - * @param eventClass the class which the {@link EventHandler} is subscribed to - * @param handler the {@link EventHandler} to register - * @since Envoy v0.2-alpha - */ - public void register(Class> eventClass, EventHandler handler) { - if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>()); - handlers.get(eventClass).add(handler); - } - - /** - * Dispatches a {@link Event} to every {@link EventHandler} 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()::isAssignableFrom).map(handlers::get).flatMap(List::stream).forEach(h -> h.handle(event)); - } - - /** - * @return a map of all {@link EventHandler} instances currently registered at - * this {@link EventBus} with the {@link Event} classes they are - * subscribed to as keys - * @since Envoy v0.2-alpha - */ - public Map>, List> getHandlers() { return handlers; } -} diff --git a/src/main/java/envoy/client/event/EventHandler.java b/src/main/java/envoy/client/event/EventHandler.java deleted file mode 100644 index ef3daea..0000000 --- a/src/main/java/envoy/client/event/EventHandler.java +++ /dev/null @@ -1,18 +0,0 @@ -package envoy.client.event; - -/** - * Project: envoy-clientChess
- * File: EventHandler.javaEvent.java
- * Created: 04.12.2019
- * - * @author Kai S. K. Engelbart - */ -public interface EventHandler { - - /** - * Consumes an event dispatched by the event bus. - * - * @param event The event dispatched by the event bus, only of supported type - */ - void handle(Event event); -} diff --git a/src/main/java/envoy/client/event/MessageCreationEvent.java b/src/main/java/envoy/client/event/MessageCreationEvent.java index 36397d9..d2e372d 100644 --- a/src/main/java/envoy/client/event/MessageCreationEvent.java +++ b/src/main/java/envoy/client/event/MessageCreationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.MessageEvent; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/MessageEvent.java b/src/main/java/envoy/client/event/MessageEvent.java deleted file mode 100644 index 1dab6e7..0000000 --- a/src/main/java/envoy/client/event/MessageEvent.java +++ /dev/null @@ -1,27 +0,0 @@ -package envoy.client.event; - -import envoy.data.Message; - -/** - * Project: envoy-client
- * File: MessageCreationEvent.java
- * Created: 4 Dec 2019
- * - * @author Kai S. K. Engelbart - */ -public class MessageEvent implements Event { - - protected final Message message; - - /** - * Initializes a {@link MessageEvent} conveying information about a - * {@link Message} object. - * - * @param message the {@link Message} object to attach to this event - * @since Envoy v0.2-alpha - */ - public MessageEvent(Message message) { this.message = message; } - - @Override - public Message get() { return message; } -} diff --git a/src/main/java/envoy/client/event/MessageModificationEvent.java b/src/main/java/envoy/client/event/MessageModificationEvent.java index 248c6f1..a5b7c41 100644 --- a/src/main/java/envoy/client/event/MessageModificationEvent.java +++ b/src/main/java/envoy/client/event/MessageModificationEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.data.Message; +import envoy.event.MessageEvent; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/event/ThemeChangeEvent.java b/src/main/java/envoy/client/event/ThemeChangeEvent.java index ac07aa1..adb9707 100644 --- a/src/main/java/envoy/client/event/ThemeChangeEvent.java +++ b/src/main/java/envoy/client/event/ThemeChangeEvent.java @@ -1,6 +1,7 @@ package envoy.client.event; import envoy.client.ui.Theme; +import envoy.event.Event; /** * Project: envoy-client
diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 5f8ff21..289fdd6 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -10,13 +10,13 @@ import javax.swing.*; import javax.swing.border.EmptyBorder; import envoy.client.*; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; import envoy.data.TextMessage; import envoy.data.User; +import envoy.event.EventBus; /** * Project: envoy-client
@@ -297,14 +297,15 @@ public class ChatWindow extends JFrame { // Synchronize try { - localDB.applySync(client.sendSync(client.getSender().getId(), localDB.fillSync(client.getSender().getId()))); + // localDB.applySync(client.sendSync(client.getSender().getId(), + // localDB.fillSync(client.getSender().getId()))); } catch (Exception e) { logger.log(Level.SEVERE, "Could not perform sync", e); } - // Process unread messages - localDB.addUnreadMessagesToLocalDB(); - localDB.clearUnreadMessagesSync(); + // TODO: Process unread messages + // localDB.addUnreadMessagesToLocalDB(); + // localDB.clearUnreadMessagesSync(); // Mark unread messages as read when they are in the current chat readCurrentChat(); @@ -325,7 +326,11 @@ public class ChatWindow extends JFrame { /** * Marks messages in the current chat as {@code READ}. */ - private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } + private void readCurrentChat() { + if (currentChat != null) { + // TODO: localDB.setMessagesToRead(currentChat); + } + } /** * Sets the {@link Client} used by this {@link ChatWindow}. If the client is diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1125030..2faaa1a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -12,6 +12,7 @@ import javax.swing.SwingUtilities; import envoy.client.*; import envoy.client.util.EnvoyLog; +import envoy.data.LoginCredentials; import envoy.data.User; import envoy.exception.EnvoyException; @@ -75,6 +76,9 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } + + // TODO: create dialog + String pass = JOptionPane.showInputDialog("Enter password"); // Initialize the local database LocalDB localDB; @@ -91,10 +95,10 @@ public class Startup { // Acquire the client user (with ID) either from the server or from the local // database, which triggers offline mode - Client client = new Client(config); + Client client = new Client(); try { // Try entering online mode first - client.onlineInit(userName); + client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); try { @@ -120,8 +124,8 @@ public class Startup { // Initialize chats in local database try { localDB.initializeDBFile(); - localDB.loadChats(); - } catch (EnvoyException e) { + // TODO: localDB.loadChats(); + } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", diff --git a/src/main/java/envoy/client/ui/StatusTrayIcon.java b/src/main/java/envoy/client/ui/StatusTrayIcon.java index 68427f6..a403799 100644 --- a/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -5,10 +5,10 @@ import java.awt.TrayIcon.MessageType; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import envoy.client.event.EventBus; import envoy.client.event.MessageCreationEvent; import envoy.data.Message; import envoy.data.TextMessage; +import envoy.event.EventBus; import envoy.exception.EnvoyException; /** diff --git a/src/main/java/envoy/client/ui/settings/SettingsScreen.java b/src/main/java/envoy/client/ui/settings/SettingsScreen.java index 611100f..533200f 100644 --- a/src/main/java/envoy/client/ui/settings/SettingsScreen.java +++ b/src/main/java/envoy/client/ui/settings/SettingsScreen.java @@ -10,11 +10,11 @@ import java.util.logging.Logger; import javax.swing.*; import envoy.client.Settings; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.PrimaryButton; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; +import envoy.event.EventBus; /** * This class provides the GUI to change the user specific settings.
diff --git a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java index ba5da87..9d4c6be 100644 --- a/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java +++ b/src/main/java/envoy/client/ui/settings/ThemeCustomizationPanel.java @@ -10,11 +10,11 @@ import java.util.logging.Logger; import javax.swing.*; import envoy.client.Settings; -import envoy.client.event.EventBus; import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.Color; import envoy.client.ui.Theme; import envoy.client.util.EnvoyLog; +import envoy.event.EventBus; /** * Displays GUI components that allow changing the current {@Theme} and creating diff --git a/src/main/java/envoy/client/util/SerializationUtils.java b/src/main/java/envoy/client/util/SerializationUtils.java deleted file mode 100644 index f0cc70f..0000000 --- a/src/main/java/envoy/client/util/SerializationUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -package envoy.client.util; - -import java.io.*; - -import envoy.exception.EnvoyException; - -/** - * Project: envoy-clientChess
- * File: SerializationUtils.javaEvent.java
- * Created: 23.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public class SerializationUtils { - - private SerializationUtils() {} - - /** - * Deserializes an arbitrary {@link Serializable} object from a file. - * - * @param the type of the object to deserialize - * @param file the file deserialize from - * @param serializedClass the class of the object to deserialize - * @return the deserialized object - * @throws EnvoyException if an error occurred during deserialization - * @since Envoy v0.3-alpha - */ - public static T read(File file, Class serializedClass) throws EnvoyException { - if (file == null) throw new NullPointerException("File is null"); - try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { - return serializedClass.cast(in.readObject()); - } catch (ClassNotFoundException | IOException e) { - throw new EnvoyException("Could not load serialized object", e); - } - } - - /** - * Serializes an arbitrary object to a file. - * - * @param file the file to serialize to - * @param obj the object to serialize - * @throws IOException if an error occurred during serialization - * @since Envoy v0.3-alpha - */ - public static void write(File file, Object obj) throws IOException { - if (file == null) throw new NullPointerException("File is null"); - if (obj == null) throw new NullPointerException("Object to serialize is null"); - if (!file.exists()) { - file.getParentFile().mkdirs(); - file.createNewFile(); - } - try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { - out.writeObject(obj); - } - } -} \ No newline at end of file From c06a2e8c375c8b3eda344ba651d4569ea3de4a4f Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 30 Dec 2019 18:18:03 +0200 Subject: [PATCH 03/10] Receiving objects from server on separate thread --- src/main/java/envoy/client/Client.java | 38 ++++++++------ .../java/envoy/client/ObjectProcessor.java | 15 ++++++ src/main/java/envoy/client/Receiver.java | 50 +++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 1 + 4 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 src/main/java/envoy/client/ObjectProcessor.java create mode 100644 src/main/java/envoy/client/Receiver.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 6a4b754..a037e8c 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,7 +1,5 @@ package envoy.client; -import java.io.IOException; -import java.io.InputStream; import java.net.Socket; import java.util.Map; import java.util.logging.Logger; @@ -9,6 +7,7 @@ import java.util.logging.Logger; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; import envoy.data.User; +import envoy.exception.EnvoyException; import envoy.util.SerializationUtils; /** @@ -23,10 +22,11 @@ import envoy.util.SerializationUtils; */ public class Client { - private Socket socket; - private Config config = Config.getInstance(); - private User sender, recipient; - private boolean online; + private Socket socket; + private Config config = Config.getInstance(); + private volatile User sender; + private User recipient; + private boolean online; private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); @@ -34,11 +34,11 @@ public class Client { * Enters the online mode by acquiring a user ID from the server. * * @param credentials the login credentials of the user - * @throws IOException if the online mode could not be entered or the request - * failed for some other reason + * @throws Exception if the online mode could not be entered or the request + * failed for some other reason * @since Envoy v0.2-alpha */ - public void onlineInit(LoginCredentials credentials) throws IOException { + public void onlineInit(LoginCredentials credentials) throws Exception { logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); logger.info("Successfully connected to server."); @@ -47,14 +47,20 @@ public class Client { logger.finest("Sending login credentials..."); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Read response (user object) - InputStream in = socket.getInputStream(); + // Create message receiver + Receiver receiver = new Receiver(socket.getInputStream()); - // Read object - try { - sender = SerializationUtils.read(in, User.class); - } catch (ClassNotFoundException e) { - throw new IOException(e); + // Register user creation processor + receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + + // Start receiver + new Thread(receiver).start(); + + // Wait for a maximum of five seconds to acquire the sender object + long start = System.currentTimeMillis(); + while (sender == null) { + if (System.currentTimeMillis() - start > 5000) throw new EnvoyException("Did not log in after 5 seconds"); + Thread.sleep(500); } online = true; diff --git a/src/main/java/envoy/client/ObjectProcessor.java b/src/main/java/envoy/client/ObjectProcessor.java new file mode 100644 index 0000000..b0aed2d --- /dev/null +++ b/src/main/java/envoy/client/ObjectProcessor.java @@ -0,0 +1,15 @@ +package envoy.client; + + +/** + * Project: envoy-client
+ * File: ObjectProcessor.java
+ * Created: 30.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public interface ObjectProcessor { + + void process(T input); +} \ No newline at end of file diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java new file mode 100644 index 0000000..64a4655 --- /dev/null +++ b/src/main/java/envoy/client/Receiver.java @@ -0,0 +1,50 @@ +package envoy.client; + +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import envoy.client.util.EnvoyLog; + +/** + * Project: envoy-client
+ * File: Receiver.java
+ * Created: 30.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class Receiver implements Runnable { + + private InputStream in; + private Map, ObjectProcessor> processors = new HashMap<>(); + + private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); + + public Receiver(InputStream in) { this.in = in; } + + @SuppressWarnings("unchecked") + @Override + public void run() { + try (ObjectInputStream oin = new ObjectInputStream(in)) { + while (true) { + Object obj = oin.readObject(); + logger.finest("Received object " + obj); + + // Get appropriate processor + ObjectProcessor processor = processors.get(obj.getClass()); + if (processor == null) + logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); + else + processor.process(obj); + } + } catch(Exception e) { + logger.log(Level.SEVERE, "Error on receiver thread", e); + } + } + + public void registerProcessor(Class processorClass, ObjectProcessor processor) { processors.put(processorClass, processor); } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 2faaa1a..1a2c96e 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -101,6 +101,7 @@ public class Startup { client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); + e1.printStackTrace(); try { // Try entering offline mode localDB.loadUsers(); From 22ccddcc39c07fc4a01bef0d6e2617dd68c7db1c Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 11:27:52 +0200 Subject: [PATCH 04/10] Integrated the new Message class from envoy-common --- src/main/java/envoy/client/ui/ChatWindow.java | 4 ++-- src/main/java/envoy/client/ui/MessageListRenderer.java | 10 ++++------ src/main/java/envoy/client/ui/StatusTrayIcon.java | 8 +++----- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 289fdd6..591be9f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -14,7 +14,7 @@ import envoy.client.event.ThemeChangeEvent; import envoy.client.ui.settings.SettingsScreen; import envoy.client.util.EnvoyLog; import envoy.data.Message; -import envoy.data.TextMessage; +import envoy.data.MessageBuilder; import envoy.data.User; import envoy.event.EventBus; @@ -247,7 +247,7 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = new TextMessage(0, localDB.getUser(), currentChat.getRecipient(), messageEnterTextArea.getText()); + final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 967b1cc..33f36f9 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -9,7 +9,6 @@ import javax.swing.ListCellRenderer; import envoy.client.Settings; import envoy.data.Message; -import envoy.data.TextMessage; /** * Defines how a message is displayed.
@@ -38,12 +37,11 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer { // TODO: Handle other message types - if (displayMessages) trayIcon.displayMessage("New message received", - ((TextMessage) ((MessageCreationEvent) evt).get()).getContent(), - MessageType.INFO); + if (displayMessages) + trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getText(), MessageType.INFO); }); } @@ -99,4 +97,4 @@ public class StatusTrayIcon { throw new EnvoyException("Could not attach Envoy tray icon to system tray.", e); } } -} +} \ No newline at end of file From 1fec53f35acc11ba4d950cc74bd05b6277829140 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 11:57:11 +0200 Subject: [PATCH 05/10] Added Client#sendMessage(Message), closing socket on exit --- src/main/java/envoy/client/Client.java | 45 +++++++++++++++---- .../java/envoy/client/ObjectProcessor.java | 15 ------- src/main/java/envoy/client/Receiver.java | 27 ++++++++--- src/main/java/envoy/client/ui/ChatWindow.java | 7 ++- src/main/java/envoy/client/ui/Startup.java | 31 ++++++++----- 5 files changed, 81 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/envoy/client/ObjectProcessor.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index a037e8c..b87f31d 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,11 +1,14 @@ package envoy.client; +import java.io.Closeable; +import java.io.IOException; import java.net.Socket; import java.util.Map; import java.util.logging.Logger; import envoy.client.util.EnvoyLog; import envoy.data.LoginCredentials; +import envoy.data.Message; import envoy.data.User; import envoy.exception.EnvoyException; import envoy.util.SerializationUtils; @@ -20,13 +23,16 @@ import envoy.util.SerializationUtils; * @author Leon Hofmeister * @since Envoy v0.1-alpha */ -public class Client { +public class Client implements Closeable { + + private Socket socket; + private Receiver receiver; + private boolean online; - private Socket socket; - private Config config = Config.getInstance(); private volatile User sender; private User recipient; - private boolean online; + + private Config config = Config.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); @@ -39,20 +45,21 @@ public class Client { * @since Envoy v0.2-alpha */ public void onlineInit(LoginCredentials credentials) throws Exception { + // Establish TCP connection logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); socket = new Socket(config.getServer(), config.getPort()); logger.info("Successfully connected to server."); - // Write login credentials - logger.finest("Sending login credentials..."); - SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Create message receiver - Receiver receiver = new Receiver(socket.getInputStream()); + receiver = new Receiver(socket.getInputStream()); // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + // Write login credentials + logger.finest("Sending login credentials..."); + SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); + // Start receiver new Thread(receiver).start(); @@ -66,6 +73,18 @@ public class Client { online = true; } + /** + * Sends a message to the server. + * + * @param message the message to send + * @throws IOException if the message does not reach the server + * @since Envoy v0.3-alpha + */ + public void sendMessage(Message message) throws IOException { + if (!online) throw new IllegalStateException("Client is not online"); + SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); + } + /** * @return a {@code Map} of all users on the server with their * user names as keys @@ -76,6 +95,9 @@ public class Client { return null; } + @Override + public void close() throws IOException { if (online) socket.close(); } + /** * @return the sender object that represents this client. * @since Envoy v0.1-alpha @@ -110,6 +132,11 @@ public class Client { */ public boolean hasRecipient() { return recipient != null; } + /** + * @return the {@link Receiver} used by this {@link Client} + */ + public Receiver getReceiver() { return receiver; } + /** * @return {@code true} if a connection to the server could be established * @since Envoy v0.2-alpha diff --git a/src/main/java/envoy/client/ObjectProcessor.java b/src/main/java/envoy/client/ObjectProcessor.java deleted file mode 100644 index b0aed2d..0000000 --- a/src/main/java/envoy/client/ObjectProcessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package envoy.client; - - -/** - * Project: envoy-client
- * File: ObjectProcessor.java
- * Created: 30.12.2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.3-alpha - */ -public interface ObjectProcessor { - - void process(T input); -} \ No newline at end of file diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index 64a4655..f70d6f9 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -4,6 +4,7 @@ import java.io.InputStream; import java.io.ObjectInputStream; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; @@ -19,11 +20,16 @@ import envoy.client.util.EnvoyLog; */ public class Receiver implements Runnable { - private InputStream in; - private Map, ObjectProcessor> processors = new HashMap<>(); + private InputStream in; + private Map, Consumer> processors = new HashMap<>(); private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); + /** + * Creates an instance of {@link Receiver}. + * + * @param in the {@link InputStream} to parse objects from + */ public Receiver(InputStream in) { this.in = in; } @SuppressWarnings("unchecked") @@ -35,16 +41,23 @@ public class Receiver implements Runnable { logger.finest("Received object " + obj); // Get appropriate processor - ObjectProcessor processor = processors.get(obj.getClass()); + @SuppressWarnings("rawtypes") + Consumer processor = processors.get(obj.getClass()); if (processor == null) logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); - else - processor.process(obj); + else processor.accept(obj); } - } catch(Exception e) { + } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); } } - public void registerProcessor(Class processorClass, ObjectProcessor processor) { processors.put(processorClass, processor); } + /** + * Adds an object processor to this {@link Receiver}. It will be called once an + * object of the accepted class has been received. + * + * @param processorClass the object class accepted by the processor + * @param processor the object processor + */ + public void registerProcessor(Class processorClass, Consumer processor) { processors.put(processorClass, processor); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 591be9f..b839c4c 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -246,8 +246,13 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { - // Create and send message object + // Create message final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); + + // Send message + client.sendMessage(message); + + // Add message to LocalDB and update UI currentChat.appendMessage(message); messageList.setModel(currentChat.getModel()); diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 1a2c96e..ae01e82 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -2,6 +2,7 @@ package envoy.client.ui; import java.awt.EventQueue; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -76,7 +77,7 @@ public class Startup { logger.severe("User name is not set or empty. Exiting..."); System.exit(1); } - + // TODO: create dialog String pass = JOptionPane.showInputDialog("Enter password"); @@ -125,17 +126,17 @@ public class Startup { // Initialize chats in local database try { localDB.initializeDBFile(); - // TODO: localDB.loadChats(); + localDB.loadChats(); + } catch (FileNotFoundException e) { + // The local database file has not yet been created, probably first login } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, - "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", + "Error while loading local database: " + e.toString() + "\nChats might not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } - logger.info("Client user ID: " + client.getSender().getId()); - // Save all users to the local database if (client.isOnline()) localDB.setUsers(client.getUsers()); @@ -147,8 +148,13 @@ public class Startup { try { new StatusTrayIcon(chatWindow).show(); - // If the tray icon is supported and corresponding settings is set, hide the chat window on close - Settings.getInstance().getItems().get("onCloseMode").setChangeHandler((onCloseMode) -> chatWindow.setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); + // If the tray icon is supported and corresponding settings is set, hide the + // chat window on close + Settings.getInstance() + .getItems() + .get("onCloseMode") + .setChangeHandler((onCloseMode) -> chatWindow + .setDefaultCloseOperation((boolean) onCloseMode ? JFrame.HIDE_ON_CLOSE : JFrame.EXIT_ON_CLOSE)); } catch (EnvoyException e) { logger.warning("The StatusTrayIcon is not supported on this platform!"); } @@ -160,13 +166,14 @@ public class Startup { // Save Settings and LocalDB on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { - logger.info("Saving local database..."); + logger.info("Closing connection..."); + client.close(); + + logger.info("Saving local database and settings..."); localDB.save(); - logger.info("Saving settings..."); Settings.getInstance().save(); - } catch (IOException e1) { - e1.printStackTrace(); - logger.log(Level.WARNING, "Unable to save the messages", e1); + } catch (IOException e) { + logger.log(Level.SEVERE, "Unable to save local files", e); } })); } From fde3ae2859cef9f86c14112d41f55a492d6030ed Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Tue, 31 Dec 2019 16:38:52 +0200 Subject: [PATCH 06/10] Acquiring user list through the sender object --- src/main/java/envoy/client/Client.java | 17 +++++++++++------ src/main/java/envoy/client/LocalDB.java | 4 ---- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index b87f31d..37fc456 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -3,6 +3,7 @@ package envoy.client; import java.io.Closeable; import java.io.IOException; import java.net.Socket; +import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; @@ -56,13 +57,13 @@ public class Client implements Closeable { // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + // Start receiver + new Thread(receiver).start(); + // Write login credentials logger.finest("Sending login credentials..."); SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); - // Start receiver - new Thread(receiver).start(); - // Wait for a maximum of five seconds to acquire the sender object long start = System.currentTimeMillis(); while (sender == null) { @@ -81,7 +82,7 @@ public class Client implements Closeable { * @since Envoy v0.3-alpha */ public void sendMessage(Message message) throws IOException { - if (!online) throw new IllegalStateException("Client is not online"); + checkOnline(); SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); } @@ -91,13 +92,17 @@ public class Client implements Closeable { * @since Envoy v0.2-alpha */ public Map getUsers() { - // TODO - return null; + checkOnline(); + Map users = new HashMap<>(); + sender.getContacts().forEach(u -> users.put(u.getName(), u)); + return users; } @Override public void close() throws IOException { if (online) socket.close(); } + private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); } + /** * @return the sender object that represents this client. * @since Envoy v0.1-alpha diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index d550c3a..5bc5421 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -3,9 +3,7 @@ package envoy.client; import java.io.File; import java.io.IOException; import java.util.*; -import java.util.logging.Logger; -import envoy.client.util.EnvoyLog; import envoy.data.User; import envoy.util.SerializationUtils; @@ -25,8 +23,6 @@ public class LocalDB { private Map users = new HashMap<>(); private List chats = new ArrayList<>(); - private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); - /** * Constructs an empty local database. To serialize any chats to the file * system, call {@link LocalDB#initializeDBFile()}. From 34785dc7f59b2e64a81d013320cd736805bee8aa Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Wed, 1 Jan 2020 18:18:18 +0200 Subject: [PATCH 07/10] Added LoginDialog --- .../java/envoy/client/ui/LoginDialog.java | 118 ++++++++++++++++++ src/main/java/envoy/client/ui/Startup.java | 22 ++-- 2 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/main/java/envoy/client/ui/LoginDialog.java diff --git a/src/main/java/envoy/client/ui/LoginDialog.java b/src/main/java/envoy/client/ui/LoginDialog.java new file mode 100644 index 0000000..db88176 --- /dev/null +++ b/src/main/java/envoy/client/ui/LoginDialog.java @@ -0,0 +1,118 @@ +package envoy.client.ui; + +import java.awt.*; +import java.security.NoSuchAlgorithmException; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; + +import envoy.data.LoginCredentials; + +/** + * Project: envoy-client
+ * File: LoginDialog.java
+ * Created: 01.01.2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class LoginDialog extends JDialog { + + private final JPanel contentPanel = new JPanel(); + + private static final long serialVersionUID = 352021600833907468L; + private JTextField textField; + private JPasswordField passwordField; + + private LoginCredentials credentials; + + /** + * Displays a dialog enabling the user to enter their user name and password. + * + * @since Envoy v0.3-alpha + */ + public LoginDialog() { + setSize(338, 123); + setLocationRelativeTo(null); + getContentPane().setLayout(new BorderLayout()); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel, BorderLayout.CENTER); + GridBagLayout gbl_contentPanel = new GridBagLayout(); + gbl_contentPanel.columnWidths = new int[] { 0, 0, 0 }; + gbl_contentPanel.rowHeights = new int[] { 0, 0, 0 }; + gbl_contentPanel.columnWeights = new double[] { 0.0, 1.0, Double.MIN_VALUE }; + gbl_contentPanel.rowWeights = new double[] { 0.0, 0.0, Double.MIN_VALUE }; + contentPanel.setLayout(gbl_contentPanel); + { + JLabel lblUserName = new JLabel("User name:"); + GridBagConstraints gbc_lblUserName = new GridBagConstraints(); + gbc_lblUserName.anchor = GridBagConstraints.EAST; + gbc_lblUserName.insets = new Insets(0, 0, 5, 5); + gbc_lblUserName.gridx = 0; + gbc_lblUserName.gridy = 0; + contentPanel.add(lblUserName, gbc_lblUserName); + } + { + textField = new JTextField(); + GridBagConstraints gbc_textField = new GridBagConstraints(); + gbc_textField.insets = new Insets(0, 0, 5, 0); + gbc_textField.fill = GridBagConstraints.HORIZONTAL; + gbc_textField.gridx = 1; + gbc_textField.gridy = 0; + contentPanel.add(textField, gbc_textField); + textField.setColumns(10); + } + { + JLabel lblPassword = new JLabel("Password:"); + GridBagConstraints gbc_lblPassword = new GridBagConstraints(); + gbc_lblPassword.anchor = GridBagConstraints.EAST; + gbc_lblPassword.insets = new Insets(0, 0, 0, 5); + gbc_lblPassword.gridx = 0; + gbc_lblPassword.gridy = 1; + contentPanel.add(lblPassword, gbc_lblPassword); + } + { + passwordField = new JPasswordField(); + GridBagConstraints gbc_passwordField = new GridBagConstraints(); + gbc_passwordField.fill = GridBagConstraints.HORIZONTAL; + gbc_passwordField.gridx = 1; + gbc_passwordField.gridy = 1; + contentPanel.add(passwordField, gbc_passwordField); + } + { + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT)); + getContentPane().add(buttonPane, BorderLayout.SOUTH); + { + JButton okButton = new JButton("OK"); + okButton.addActionListener((evt) -> { + try { + credentials = new LoginCredentials(textField.getText(), passwordField.getPassword()); + dispose(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + }); + okButton.setActionCommand("OK"); + buttonPane.add(okButton); + getRootPane().setDefaultButton(okButton); + } + { + JButton cancelButton = new JButton("Cancel"); + cancelButton.addActionListener((evt) -> dispose()); + cancelButton.setActionCommand("Cancel"); + buttonPane.add(cancelButton); + } + } + + setModal(true); + setVisible(true); + } + + /** + * @return the {@link LoginCredentials} entered by the user, or {@code null} if + * the dialog has been cancelled + * @since Envoy v0.3-alpha + */ + public LoginCredentials getCredentials() { return credentials; } +} \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index ae01e82..3e4692d 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -71,15 +71,13 @@ public class Startup { EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier()); EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier()); - // Ask the user for their user name - String userName = JOptionPane.showInputDialog("Please enter your username"); - if (userName == null || userName.isEmpty()) { - logger.severe("User name is not set or empty. Exiting..."); - System.exit(1); - } + // Ask the user for their user name and password + LoginCredentials credentials = new LoginDialog().getCredentials(); - // TODO: create dialog - String pass = JOptionPane.showInputDialog("Enter password"); + if (credentials == null) { + logger.info("The login process has been aborted by the user. Exiting..."); + System.exit(0); + } // Initialize the local database LocalDB localDB; @@ -99,18 +97,18 @@ public class Startup { Client client = new Client(); try { // Try entering online mode first - client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); + client.onlineInit(credentials); } catch (Exception e1) { logger.warning("Could not connect to server. Trying offline mode..."); e1.printStackTrace(); try { // Try entering offline mode localDB.loadUsers(); - User clientUser = localDB.getUsers().get(userName); + User clientUser = localDB.getUsers().get(credentials.getName()); if (clientUser == null) throw new EnvoyException("Could not enter offline mode: user name unknown"); client.setSender(clientUser); JOptionPane.showMessageDialog(null, - "A connection to the server could not be established. Starting in offline mode.", + "A connection to the server could not be established. Starting in offline mode.\n" + e1, "Connection error", JOptionPane.WARNING_MESSAGE); } catch (Exception e2) { @@ -132,7 +130,7 @@ public class Startup { } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(null, - "Error while loading local database: " + e.toString() + "\nChats might not be stored locally.", + "Error while loading local database: " + e + "\nChats might not be stored locally.", "Local DB error", JOptionPane.WARNING_MESSAGE); } From 655ac58f3293ef6f6b6f79975bbe7a6d7aa8eed9 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Thu, 2 Jan 2020 17:11:41 +0200 Subject: [PATCH 08/10] Added contact initialization to handshake and ReceivedMessageProcessor --- src/main/java/envoy/client/Client.java | 29 +++- src/main/java/envoy/client/LocalDB.java | 160 ------------------ .../client/ReceivedMessageProcessor.java | 32 ++++ src/main/java/envoy/client/Receiver.java | 12 +- 4 files changed, 63 insertions(+), 170 deletions(-) create mode 100644 src/main/java/envoy/client/ReceivedMessageProcessor.java diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 37fc456..4885a92 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -7,11 +7,10 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; +import javax.naming.TimeLimitExceededException; + import envoy.client.util.EnvoyLog; -import envoy.data.LoginCredentials; -import envoy.data.Message; -import envoy.data.User; -import envoy.exception.EnvoyException; +import envoy.data.*; import envoy.util.SerializationUtils; /** @@ -33,12 +32,17 @@ public class Client implements Closeable { private volatile User sender; private User recipient; + private volatile Contacts contacts; + private Config config = Config.getInstance(); private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); /** - * Enters the online mode by acquiring a user ID from the server. + * 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 + * will block for up to 5 seconds. If the handshake does exceed this time limit, + * an exception is thrown. * * @param credentials the login credentials of the user * @throws Exception if the online mode could not be entered or the request @@ -56,6 +60,7 @@ public class Client implements Closeable { // Register user creation processor receiver.registerProcessor(User.class, sender -> { logger.info("Acquired user object " + sender); this.sender = sender; }); + receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; }); // Start receiver new Thread(receiver).start(); @@ -66,12 +71,19 @@ public class Client implements Closeable { // Wait for a maximum of five seconds to acquire the sender object long start = System.currentTimeMillis(); - while (sender == null) { - if (System.currentTimeMillis() - start > 5000) throw new EnvoyException("Did not log in after 5 seconds"); + while (sender == null || contacts == null) { + if (System.currentTimeMillis() - start > 5000) throw new TimeLimitExceededException("Did not log in after 5 seconds"); Thread.sleep(500); } + logger.info("Handshake completed."); online = true; + + // Remove user creation processor + receiver.removeAllProcessors(); + + // Register processors for message and status handling + receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); } /** @@ -84,6 +96,7 @@ public class Client implements Closeable { public void sendMessage(Message message) throws IOException { checkOnline(); SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); + message.nextStatus(); } /** @@ -94,7 +107,7 @@ public class Client implements Closeable { public Map getUsers() { checkOnline(); Map users = new HashMap<>(); - sender.getContacts().forEach(u -> users.put(u.getName(), u)); + contacts.getContacts().forEach(u -> users.put(u.getName(), u)); return users; } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 5bc5421..2c40e65 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -84,166 +84,6 @@ public class LocalDB { */ public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } - // /** - // * Creates a {@link Sync} object filled with the changes that occurred to the - // * local database since the last synchronization. - // * - // * @param userId the ID of the user that is synchronized by this client - // * @return {@link Sync} object filled with the current changes - // * @since Envoy v0.1-alpha - // */ - // public Sync fillSync(long userId) { - // addWaitingMessagesToSync(); - // - // sync.getMessages().addAll(readMessages.getMessages()); - // readMessages.getMessages().clear(); - // - // logger.finest(String.format("Filled sync with %d messages.", - // sync.getMessages().size())); - // return sync; - // } - // - // /** - // * Applies the changes carried by a {@link Sync} object to the local database - // * - // * @param returnSync the {@link Sync} object to apply - // * @since Envoy v0.1-alpha - // */ - // public void applySync(Sync returnSync) { - // for (int i = 0; i < returnSync.getMessages().size(); i++) { - // - // // The message has an ID - // if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { - // - // // Messages are processes differently corresponding to their state - // switch (returnSync.getMessages().get(i).getMetadata().getState()) { - // case SENT: - // // Update previously waiting and now sent messages that were assigned an ID - // by - // // the server - // sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); - // sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // break; - // case RECEIVED: - // if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { - // // these are the unread Messages from the server - // unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); - // - // // Create and dispatch message creation event - // EventBus.getInstance().dispatch(new - // MessageCreationEvent(returnSync.getMessages().get(i))); - // } else { - // // Update Messages in localDB to state RECEIVED - // for (Chat chat : getChats()) - // if (chat.getRecipient().getId() == - // returnSync.getMessages().get(i).getMetadata().getRecipient()) - // for (int j = 0; j < chat.getModel().getSize(); j++) - // if (chat.getModel().get(j).getMetadata().getMessageId() == - // returnSync.getMessages() - // .get(i) - // .getMetadata() - // .getMessageId()) - // chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // } - // break; - // case READ: - // // Update local Messages to state READ - // logger.info("Message with ID: " + - // returnSync.getMessages().get(i).getMetadata().getMessageId() - // + "was initialized to be set to READ in localDB."); - // for (Chat chat : getChats()) - // if (chat.getRecipient().getId() == - // returnSync.getMessages().get(i).getMetadata().getRecipient()) { - // logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); - // for (int k = 0; k < chat.getModel().getSize(); k++) - // if (chat.getModel().get(k).getMetadata().getMessageId() == - // returnSync.getMessages() - // .get(i) - // .getMetadata() - // .getMessageId()) { - // logger.info("Message with ID: " + - // chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); - // chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); - // logger.info("Message State is now: " + - // chat.getModel().get(k).getMetadata().getState()); - // } - // } - // break; - // } - // } - // } - // - // // Updating UserStatus of all users in LocalDB - // for (User user : returnSync.getUsers()) - // for (Chat chat : getChats()) - // if (user.getId() == chat.getRecipient().getId()) - // chat.getRecipient().setStatus(user.getStatus()); - // - // sync.getMessages().clear(); - // sync.getUsers().clear(); - // } - // - // /** - // * Adds the unread messages returned from the server in the latest sync to the - // * right chats in the LocalDB. - // * - // * @since Envoy v0.1-alpha - // */ - // public void addUnreadMessagesToLocalDB() { - // for (Message message : unreadMessagesSync.getMessages()) - // for (Chat chat : getChats()) - // if (message.getMetadata().getSender() == chat.getRecipient().getId()) { - // chat.appendMessage(message); - // break; - // } - // } - // - // /** - // * Changes all messages with state {@code RECEIVED} of a specific chat to - // state - // * {@code READ}. - // *
- // * Adds these messages to the {@code readMessages} {@link Sync} object. - // * - // * @param currentChat the {@link Chat} that was just opened - // * @since Envoy v0.1-alpha - // */ - // public void setMessagesToRead(Chat currentChat) { - // for (int i = currentChat.getModel().size() - 1; i >= 0; --i) - // if (currentChat.getModel().get(i).getMetadata().getRecipient() != - // currentChat.getRecipient().getId()) - // if (currentChat.getModel().get(i).getMetadata().getState() == - // MessageState.RECEIVED) { - // currentChat.getModel().get(i).getMetadata().setState(MessageState.READ); - // readMessages.getMessages().add(currentChat.getModel().get(i)); - // } else break; - // } - // - // /** - // * Adds all messages with state {@code WAITING} from the {@link LocalDB} to - // the - // * {@link Sync} object. - // * - // * @since Envoy v0.1-alpha - // */ - // private void addWaitingMessagesToSync() { - // for (Chat chat : getChats()) - // for (int i = 0; i < chat.getModel().size(); i++) - // if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) - // { - // logger.info("Got Waiting Message"); - // sync.getMessages().add(chat.getModel().get(i)); - // } - // } - // - // /** - // * Clears the {@code unreadMessagesSync} {@link Sync} object. - // * - // * @since Envoy v0.1-alpha - // */ - // public void clearUnreadMessagesSync() { - // unreadMessagesSync.getMessages().clear(); } - /** * @return a {@code Map} of all users stored locally with their * user names as keys diff --git a/src/main/java/envoy/client/ReceivedMessageProcessor.java b/src/main/java/envoy/client/ReceivedMessageProcessor.java new file mode 100644 index 0000000..d408993 --- /dev/null +++ b/src/main/java/envoy/client/ReceivedMessageProcessor.java @@ -0,0 +1,32 @@ +package envoy.client; + +import java.util.function.Consumer; +import java.util.logging.Logger; + +import envoy.client.event.MessageCreationEvent; +import envoy.client.util.EnvoyLog; +import envoy.data.Message; +import envoy.data.Message.MessageStatus; +import envoy.event.EventBus; + +/** + * Project: envoy-client
+ * File: ReceivedMessageProcessor.java
+ * Created: 31.12.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class ReceivedMessageProcessor implements Consumer { + + private static final Logger logger = EnvoyLog.getLogger(ReceivedMessageProcessor.class.getSimpleName()); + + @Override + public void accept(Message message) { + logger.info("Received message object " + message); + if (message.getStatus() != MessageStatus.SENT) logger.warning("The message has the unexpected status " + message.getStatus()); + else + // Dispatch event + EventBus.getInstance().dispatch(new MessageCreationEvent(message)); + } +} diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index f70d6f9..abe4687 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -2,6 +2,7 @@ package envoy.client; import java.io.InputStream; import java.io.ObjectInputStream; +import java.net.SocketException; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; @@ -20,8 +21,8 @@ import envoy.client.util.EnvoyLog; */ public class Receiver implements Runnable { - private InputStream in; - private Map, Consumer> processors = new HashMap<>(); + private final InputStream in; + private final Map, Consumer> processors = new HashMap<>(); private static final Logger logger = EnvoyLog.getLogger(Receiver.class.getSimpleName()); @@ -47,6 +48,8 @@ public class Receiver implements Runnable { logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); else processor.accept(obj); } + } catch (SocketException e) { + logger.info("Connection probably closed by client. Exiting receiver thread..."); } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); } @@ -60,4 +63,9 @@ public class Receiver implements Runnable { * @param processor the object processor */ public void registerProcessor(Class processorClass, Consumer processor) { processors.put(processorClass, processor); } + + /** + * Removes all object processors registered at this {@link Receiver}. + */ + public void removeAllProcessors() { processors.clear(); } } \ No newline at end of file From d005bcd4c976eaf4d4aff48a8297bb2e53383fb8 Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 6 Jan 2020 15:00:44 +0200 Subject: [PATCH 09/10] Adjusted message creation to the updated MessageBuilder. --- src/main/java/envoy/client/ui/ChatWindow.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index b839c4c..4f8b0dc 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -247,7 +247,9 @@ public class ChatWindow extends JFrame { if (!messageEnterTextArea.getText().isEmpty()) try { // Create message - final Message message = new MessageBuilder(localDB.getUser(), currentChat.getRecipient()).setText(messageEnterTextArea.getText()).build(); + final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId()) + .setText(messageEnterTextArea.getText()) + .build(); // Send message client.sendMessage(message); From 80fc11f91e5a922b550ef9ed1ff340fb65cf0ded Mon Sep 17 00:00:00 2001 From: CyB3RC0nN0R Date: Mon, 6 Jan 2020 17:37:38 +0100 Subject: [PATCH 10/10] Fixed ObjectInputStream header error by reading chunks. --- .classpath | 6 ---- src/main/java/envoy/client/Receiver.java | 39 ++++++++++++++++-------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.classpath b/.classpath index 1a0c560..a5d9509 100644 --- a/.classpath +++ b/.classpath @@ -28,11 +28,5 @@ - - - - - - diff --git a/src/main/java/envoy/client/Receiver.java b/src/main/java/envoy/client/Receiver.java index abe4687..e6cd3c5 100644 --- a/src/main/java/envoy/client/Receiver.java +++ b/src/main/java/envoy/client/Receiver.java @@ -1,5 +1,6 @@ package envoy.client; +import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.net.SocketException; @@ -10,12 +11,13 @@ import java.util.logging.Level; import java.util.logging.Logger; import envoy.client.util.EnvoyLog; +import envoy.util.SerializationUtils; /** * Project: envoy-client
* File: Receiver.java
* Created: 30.12.2019
- * + * * @author Kai S. K. Engelbart * @since Envoy v0.3-alpha */ @@ -36,29 +38,42 @@ public class Receiver implements Runnable { @SuppressWarnings("unchecked") @Override public void run() { - try (ObjectInputStream oin = new ObjectInputStream(in)) { - while (true) { - Object obj = oin.readObject(); - logger.finest("Received object " + obj); - // Get appropriate processor - @SuppressWarnings("rawtypes") - Consumer processor = processors.get(obj.getClass()); - if (processor == null) - logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); - else processor.accept(obj); + try { + while (true) { + // Read object length + byte[] lenBytes = new byte[4]; + in.read(lenBytes); + int len = SerializationUtils.bytesToInt(lenBytes, 0); + + // Read object into byte array + byte[] objBytes = new byte[len]; + in.read(objBytes); + + try (ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(objBytes))) { + Object obj = oin.readObject(); + logger.finest("Received object " + obj); + + // Get appropriate processor + @SuppressWarnings("rawtypes") + Consumer processor = processors.get(obj.getClass()); + if (processor == null) + logger.severe(String.format("The received object has the class %s for which no processor is defined.", obj.getClass())); + else processor.accept(obj); + } } } catch (SocketException e) { logger.info("Connection probably closed by client. Exiting receiver thread..."); } catch (Exception e) { logger.log(Level.SEVERE, "Error on receiver thread", e); + e.printStackTrace(); } } /** * Adds an object processor to this {@link Receiver}. It will be called once an * object of the accepted class has been received. - * + * * @param processorClass the object class accepted by the processor * @param processor the object processor */