diff --git a/.classpath b/.classpath index d2bc4e0..906bfce 100644 --- a/.classpath +++ b/.classpath @@ -18,12 +18,6 @@ - - - - - - diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index a0878e2..522d44f 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -1,8 +1,5 @@ package envoy.client; -import java.time.Instant; -import java.util.Arrays; - import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; @@ -10,15 +7,10 @@ import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; -import javax.xml.datatype.DatatypeConfigurationException; -import javax.xml.datatype.DatatypeFactory; -import envoy.schema.Message; -import envoy.schema.Message.MetaData.MessageState; -import envoy.schema.Messages; import envoy.schema.ObjectFactory; +import envoy.schema.Sync; import envoy.schema.User; -import envoy.schema.Users; /** * Project: envoy-client
@@ -33,89 +25,47 @@ import envoy.schema.Users; public class Client { private ObjectFactory objectFactory = new ObjectFactory(); - private DatatypeFactory datatypeFactory; private Config config; private User sender, recipient; public Client(Config config, String username) { - this.config = config; - try { - datatypeFactory = DatatypeFactory.newInstance(); - } catch (DatatypeConfigurationException e) { - e.printStackTrace(); - } - sender = getUser(username); + this.config = config; + sender = getUser(username); + System.out.println("ID: " + sender.getID()); + } + + 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(); + + return responseBody; + } /** - * Sends a message with text content to the server.
- * Because sending a request is a blocking operation, it is executed - * asynchronously. + * Returns a {@link Sync} with all users on the server. * - * @param message the {@link Message} we want to send + * @return Sync - List of all users on the server. * @since Envoy v0.1-alpha */ - public void sendMessage(Message message) { - new Thread(() -> { - // Wrap single message into messages list - Messages messages = wrapMessages(message); + public Sync getUsersListXml() { + Sync sendSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setID(-1); + sendSync.getUsers().add(user); - // Print message XML to console - JAXBContext jc; - try { - jc = JAXBContext.newInstance("envoy.schema"); - Marshaller m = jc.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); - m.marshal(messages, System.out); - } catch (JAXBException e) { - e.printStackTrace(); - } + Sync returnSendSync = post( + String + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + sendSync, + Sync.class); + return returnSendSync; - // Send message - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client - .target(String.format("%s:%d/envoy-server/rest/message/send", config.getServer(), config.getPort())); - - Response response = target.request().post(Entity.entity(messages, "application/xml")); - System.out.println("Response code: " + response.getStatus()); - response.close(); - client.close(); - }).start(); - } - - /** - * Creates a {@link Message} object serializable to XML. - * - * @param textContent The content (text) of the message - * @return prepared {@link Message} object - * @since Envoy v0.1-alpha - */ - public Message createMessage(String textContent) { - Message.MetaData metaData = objectFactory.createMessageMetaData(); - metaData.setSender(sender.getID()); - metaData.setRecipient(recipient.getID()); - 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; - } - - public Users getUsersListXml() { - return get(String.format("%s:%d/envoy-server/rest/user", config.getServer(), config.getPort()), Users.class); - } - - public Messages getUnreadMessages(long userId) { - return get(String - .format("%s:%d/envoy-server/rest/message/receive?userId=%d", config.getServer(), config.getPort(), userId), - Messages.class); } /** @@ -126,66 +76,104 @@ public class Client { * @since Envoy v0.1-alpha */ private User getUser(String name) { - return get( + Sync senderSync = objectFactory.createSync(); + User user = objectFactory.createUser(); + user.setName(name); + senderSync.getUsers().add(user); + + Sync returnSenderSync = post( String - .format("%s:%d/envoy-server/rest/user/sender?name=%s", config.getServer(), config.getPort(), name), - Users.class).getUser().get(0); + .format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), + senderSync, + Sync.class); + + User returnSender = objectFactory.createUser(); + + if (returnSenderSync.getUsers().size() == 1) { + returnSender = returnSenderSync.getUsers().get(0); + } else { + System.out.println("ERROR exiting..."); + } + + return returnSender; } /** - * Invokes the GET method of a web service. + * 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 the type of the object returned by the web service - * @param uri the URI of the web service - * @param responseClass the class of the object returned by the web service - * @return the object returned by the web service + * @param userId * @since Envoy v0.1-alpha */ - private T get(String uri, Class responseClass) { - javax.ws.rs.client.Client client = ClientBuilder.newClient(); - WebTarget target = client.target(uri); - Response response = target.request("application/xml").get(); - T responseObject = response.readEntity(responseClass); - System.out.println("Response code: " + response.getStatus()); - response.close(); - client.close(); - return responseObject; + public Sync sendSync(long userId, Sync sync) { + // Print sync XML to console + JAXBContext jc; + try { + jc = JAXBContext.newInstance("envoy.schema"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + m.marshal(sync, System.out); + } 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); } /** - * Wraps one or more {@link Message} objects into a {@link Messages} object. - * - * @param messages the {@link Message} objects to wrap - * @return {@link Messages} object with all messages as its children - * @since Envoy v0.1-alpha - */ - private Messages wrapMessages(Message... messages) { - Messages wrapper = objectFactory.createMessages(); - wrapper.getMessage().addAll(Arrays.asList(messages)); - return wrapper; - } - - /** - * @return the sender object that represents this client + * @return the sender object that represents this client. * @since Envoy v0.1-alpha */ public User getSender() { return sender; } /** - * @return the recipient of a message + * @return the current recipient of the current chat. * @since Envoy v0.1-alpha */ public User getRecipient() { return recipient; } /** - * @param recipient the recipient to set + * Sets the recipient. + * @param recipient - the recipient to set * @since Envoy v0.1-alpha */ public void setRecipient(User recipient) { this.recipient = recipient; } - /** + /** * @return true, if a recipient is selected * @since Envoy v0.1-alpha */ public boolean hasRecipient() { return recipient != null; } } + diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index bfa1e57..c31c972 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -16,6 +16,16 @@ public class Config { private String server; private int port; private File localDB; + private int syncTimeout; + + private static Config config; + + private Config() {} + + public static Config getInstance() { + if (config == null) config = new Config(); + return config; + } /** * Defaults to the {@code client.properties} file for information. @@ -28,7 +38,8 @@ public class Config { public void load(Properties properties) { if (properties.containsKey("server")) server = properties.getProperty("server"); if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); - localDB = new File(properties.getProperty("localDB", ".\\localDB")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); + syncTimeout = Integer.parseInt(properties.getProperty("syncTimeout", "1000")); } /** @@ -53,6 +64,8 @@ public class Config { case "-db": localDB = new File(args[++i]); } + if (localDB == null) localDB = new File(".\\localDB"); + if (syncTimeout == 0) syncTimeout = 1000; } /** @@ -107,4 +120,8 @@ public class Config { * @since Envoy v0.1-alpha **/ public void setLocalDB(File localDB) { this.localDB = localDB; } + + public int getSyncTimeout() { return syncTimeout; } + + public void setSyncTimeout(int syncTimeout) { this.syncTimeout = syncTimeout; } } diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 1bab251..142b687 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -6,10 +6,18 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.time.Instant; import java.util.ArrayList; import java.util.List; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + import envoy.exception.EnvoyException; +import envoy.schema.Message; +import envoy.schema.Message.Metadata.MessageState; +import envoy.schema.ObjectFactory; +import envoy.schema.Sync; import envoy.schema.User; /** @@ -18,13 +26,15 @@ import envoy.schema.User; * Created: 27.10.2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class LocalDB { - - private File localDB; - private User client; - private List chats = new ArrayList<>(); + private File localDB; + private User sender; + private List chats = new ArrayList<>(); + private ObjectFactory objectFactory = new ObjectFactory(); + private DatatypeFactory datatypeFactory; /** * Constructs an empty local database. @@ -32,7 +42,16 @@ public class LocalDB { * @param client the user that is logged in with this client * @since Envoy v0.1-alpha **/ - public LocalDB(User sender) { this.client = sender; } + + public LocalDB(User sender) { + this.sender = sender; + try { + datatypeFactory = DatatypeFactory.newInstance(); + } catch (DatatypeConfigurationException e) { + e.printStackTrace(); + } + } + /** * Initializes the local database and fills it with values @@ -45,7 +64,7 @@ public class LocalDB { public void initializeDBFile(File localDBDir) throws EnvoyException { if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException( String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - localDB = new File(localDBDir, client.getID() + ".db"); + localDB = new File(localDBDir, sender.getID() + ".db"); if (localDB.exists()) loadFromLocalDB(); } @@ -87,6 +106,256 @@ public class LocalDB { } } + /** + * Creates a {@link Message} object serializable to XML. + * + * @param textContent The content (text) of the message + * @return prepared {@link Message} object + */ + public Message createMessage(String textContent, User recipient) { + Message.Metadata metaData = objectFactory.createMessageMetadata(); + metaData.setSender(sender.getID()); + metaData.setRecipient(recipient.getID()); + 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; + } + + private Sync unreadMessagesSync = objectFactory.createSync(); + public Sync sync = objectFactory.createSync(); + public Sync readMessages = objectFactory.createSync(); + + public Sync fillSync(long userId) { + + addWaitingMessagesToSync(); + + getSentStateMessagesFromLocalDB(); + for (int i = 0; i < readMessages.getMessages().size(); i++) { + sync.getMessages().add(readMessages.getMessages().get(i)); + } + readMessages.getMessages().clear(); + + System.out.println(sync.getMessages().size()); + return sync; + } + + public void applySync(Sync returnSync) { + for (int i = 0; i < returnSync.getMessages().size(); i++) { + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) { + // Update Local Messages with State WAITING (add Message ID and change State to + // SENT) + for (int j = 0; j < sync.getMessages().size(); j++) { + if (j == i) { + sync.getMessages() + .get(j) + .getMetadata() + .setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId()); + sync.getMessages() + .get(j) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + + } + + } + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // these are the unread Messages from the server + unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getSender() == 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) { + // Update Messages in localDB to state RECEIVED + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j) + .getRecipient() + .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync + .getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + // Update Message in LocalDB + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(j).getMetadata().getState()); + } + } + } + } + + } + + if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 + && returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) { + // Update local Messages to state READ + System.out.println("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId() + + "was initialized to be set to READ in localDB."); + for (int j = 0; j < getChats().size(); j++) { + if (getChats().get(j) + .getRecipient() + .getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { + System.out.println("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected."); + for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) { + if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync + .getMessages() + .get(i) + .getMetadata() + .getMessageId()) { + System.out.println("Message with ID: " + + getChats().get(j).getModel().get(k).getMetadata().getMessageId() + + "was selected."); + getChats().get(j) + .getModel() + .get(k) + .getMetadata() + .setState(returnSync.getMessages().get(i).getMetadata().getState()); + System.out.println("Message State is now: " + + getChats().get(j).getModel().get(k).getMetadata().getState().toString()); + } + } + } + } + + } + } + + // Updating UserStatus of all users in LocalDB + for (int j = 0; j < returnSync.getUsers().size(); j++) { + for (int k = 0; k < getChats().size(); k++) { + if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) { + + getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus()); + System.out.println(getChats().get(k).getRecipient().getStatus().toString()); + } + } + } + + sync.getMessages().clear(); + sync.getUsers().clear(); + + } + + /** + * Adds a message to the "sync" Sync object. + * + * @param message + * @since Envoy v0.1-alpha + */ + public void addMessageToSync(Message message) { sync.getMessages().add(message); } + + /** + * Adds a user to the {@code sync} {@link Sync} object. + * + * @param user + * @since Envoy v0.1-alpha + */ + public void addUserToSync(User user) { sync.getUsers().add(user); } + + /** + * Adds the unread messages returned from the server in the latest sync to the + * right chats in the LocalDB. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addUnreadMessagesToLocalDB() { + Sync unreadMessages = unreadMessagesSync; + for (int i = 0; i < unreadMessages.getMessages().size(); i++) + for (int j = 0; j < getChats().size(); j++) + if (getChats().get(j) + .getRecipient() + .getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) { + getChats().get(j).appendMessage(unreadMessages.getMessages().get(i)); + } + } + + /** + * Gets all messages with state SENT from the LocalDB and adds them to the + * "sync" Sync object. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void getSentStateMessagesFromLocalDB() { + for (int i = 0; i < getChats().size(); i++) { + for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { + if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) { + addMessageToSync(getChats().get(i).getModel().get(j)); + } + } + } + } + + /** + * Changes all messages with State RECEIVED of a specific chat to State READ. + *
+ * Adds these Messages to the {@code readMessages} {@link Sync} object. + * + * @param currentChat + * @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 a message with State WAITING to a specific chat in the LocalDB. + * + * @param message + * @param currentChat + * @since Envoy v0.1-alpha + */ + public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); } + + /** + * Adds all messages with State WAITING from the {@link LocalDB} to the Sync. + * + * @param localDB + * @since Envoy v0.1-alpha + */ + public void addWaitingMessagesToSync() { + for (int i = 0; i < getChats().size(); i++) { + for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) { + if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) { + // addMessageToSync(localDB.getChats().get(i).getModel().get(j)); + System.out.println("Got Waiting Message"); + sync.getMessages().add(0, getChats().get(i).getModel().get(j)); + } + } + } + } + + /** + * Clears the {@code unreadMessagesSync} {@link Sync} object. + * + * @since Envoy v0.1-alpha + */ + public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); } + /** * @return all saves {@link Chat} objects that list the client user as the * client @@ -98,5 +367,5 @@ public class LocalDB { * @return the User who initialised the local Database * @since Envoy v0.1-alpha */ - public User getUser() { return client; } + public User getUser() { return sender; } } diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index f8c2fcf..2a7ae11 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -27,11 +27,11 @@ import javax.swing.border.EmptyBorder; import envoy.client.Chat; import envoy.client.Client; +import envoy.client.Config; import envoy.client.LocalDB; import envoy.schema.Message; -import envoy.schema.Messages; +import envoy.schema.Sync; import envoy.schema.User; -import envoy.schema.Users; /** * Project: envoy-client
@@ -125,8 +125,8 @@ public class ChatWindow extends JFrame { if (e.getKeyCode() == KeyEvent.VK_ENTER && ((SettingsScreen.enterToSend && e.getModifiersEx() == 0) || (e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))) { - postMessage(client, messageList); + postMessage(messageList); } } @@ -164,8 +164,7 @@ public class ChatWindow extends JFrame { gbc_moveSelectionPostButton.insets = new Insets(10, 10, 10, 10); - postButton.addActionListener((evt) -> { postMessage(client, messageList); }); - + postButton.addActionListener((evt) -> { postMessage(messageList); }); contentPane.add(postButton, gbc_moveSelectionPostButton); // Settings Button @@ -223,9 +222,13 @@ public class ChatWindow extends JFrame { .findFirst() .get(); + // Set all unread messages in the chat to read + if (currentChat != null) { localDB.setMessagesToRead(currentChat); } + client.setRecipient(user); textPane.setText(currentChat.getRecipient().getName()); + messageList.setModel(currentChat.getModel()); contentPane.revalidate(); } @@ -249,37 +252,24 @@ public class ChatWindow extends JFrame { contentPane.revalidate(); loadUsersAndChats(); - startReceiverThread(5000); + startSyncThread(Config.getInstance().getSyncTimeout()); contentPane.revalidate(); } - /** - * Posts a {@link Message}. Is used only twice: Once for clicking on the - * {@code postButton}
- * and once for pressing the KeyStroke(s) to send a message ( (ctrl+)enter) - * - * @param client the client who wants to send a {@link Message} - * @param messageList the chat in which this {@link Message} belongs - * @since Envoy v0.1-alpha - */ - private void postMessage(Client client, JList messageList) { + private void postMessage(JList messageList) { if (!client.hasRecipient()) { JOptionPane.showMessageDialog(this, "Please select a recipient!", "Cannot send message", JOptionPane.INFORMATION_MESSAGE); - return; } if (!messageEnterTextArea.getText().isEmpty()) try { // Create and send message object - final Message message = client.createMessage(messageEnterTextArea.getText()); - client.sendMessage(message); - - // Append message object to chat - currentChat.appendMessage(message); + final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient()); + localDB.addWaitingMessageToLocalDB(message, currentChat); messageList.setModel(currentChat.getModel()); // Clear text field @@ -302,9 +292,9 @@ public class ChatWindow extends JFrame { */ private void loadUsersAndChats() { new Thread(() -> { - Users users = client.getUsersListXml(); + Sync users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> { + users.getUsers().forEach(user -> { userListModel.addElement(user); // Check if user exists in local DB @@ -316,21 +306,33 @@ public class ChatWindow extends JFrame { } /** - * Checks for new messages and adds them to the chat list. + * Updates the data model and the ui every x seconds. * * @param timeout the amount of time that passes between two requests sent to * the server * @since Envoy v0.1-alpha */ - private void startReceiverThread(int timeout) { + private void startSyncThread(int timeout) { new Timer(timeout, (evt) -> { - Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); - for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < localDB.getChats().size(); j++) - if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage() - .get(i) - .getMetaData() - .getSender()) localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); + new Thread(() -> { + + // Synchronize + localDB.applySync( + client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID()))); + localDB.addUnreadMessagesToLocalDB(); + localDB.clearUnreadMessagesSync(); + + // Update UI + SwingUtilities + .invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); }); + }).start(); }).start(); } + + 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()) + userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus()); + } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/MessageListRenderer.java b/src/main/java/envoy/client/ui/MessageListRenderer.java index 4490b69..9053c6c 100644 --- a/src/main/java/envoy/client/ui/MessageListRenderer.java +++ b/src/main/java/envoy/client/ui/MessageListRenderer.java @@ -18,6 +18,7 @@ import envoy.schema.Message; * Created: 19 Oct 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class MessageListRenderer extends JLabel implements ListCellRenderer { @@ -38,14 +39,16 @@ public class MessageListRenderer extends JLabel implements ListCellRenderer

%s

%s", + "

%s

%s :%s", date, - text)); + text, + state)); return this; } } \ 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 4f72026..c3a3baa 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -25,7 +25,7 @@ import envoy.exception.EnvoyException; public class Startup { public static void main(String[] args) { - Config config = new Config(); + Config config = Config.getInstance(); if (args.length > 0) { config.load(args); } else { diff --git a/src/main/java/envoy/client/ui/UserListRenderer.java b/src/main/java/envoy/client/ui/UserListRenderer.java index c0c13ba..40bb2ad 100644 --- a/src/main/java/envoy/client/ui/UserListRenderer.java +++ b/src/main/java/envoy/client/ui/UserListRenderer.java @@ -7,6 +7,7 @@ import javax.swing.JList; import javax.swing.ListCellRenderer; import envoy.schema.User; +import envoy.schema.User.UserStatus; /** * Defines how the {@code UserList} is displayed. @@ -16,6 +17,7 @@ import envoy.schema.User; * Created: 12 Oct 2019
* * @author Kai S. K. Engelbart + * @author Maximilian Käfer * @since Envoy v0.1-alpha */ public class UserListRenderer extends JLabel implements ListCellRenderer { @@ -36,8 +38,27 @@ public class UserListRenderer extends JLabel implements ListCellRenderer { // Enable background rendering setOpaque(true); - setText(value.getName()); - setFont(list.getFont()); + + final String name = value.getName(); + final UserStatus status = value.getStatus(); + + switch (status) { + case ONLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + + case OFFLINE: + setText(String.format( + "

%s

%s", + status, + name)); + break; + } + + return this; }