diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java
index 0707a62..786e96b 100644
--- a/src/main/java/envoy/client/data/Cache.java
+++ b/src/main/java/envoy/client/data/Cache.java
@@ -10,8 +10,8 @@ import java.util.logging.Logger;
import envoy.util.EnvoyLog;
/**
- * Stores elements in a queue to process them later.
- *
+ * Stores elements in a queue to process them later.
+ *
* Project: envoy-client
* File: Cache.java
* Created: 6 Feb 2020
@@ -40,6 +40,9 @@ public class Cache implements Consumer, Serializable {
elements.offer(element);
}
+ @Override
+ public String toString() { return String.format("Cache[elements=" + elements + "]"); }
+
/**
* Sets the processor to which cached elements are relayed.
*
diff --git a/src/main/java/envoy/client/data/LocalDB.java b/src/main/java/envoy/client/data/LocalDB.java
index b8dc3c9..66407fc 100644
--- a/src/main/java/envoy/client/data/LocalDB.java
+++ b/src/main/java/envoy/client/data/LocalDB.java
@@ -20,11 +20,11 @@ import envoy.event.NameChange;
*/
public abstract class LocalDB {
- protected User user;
- protected Map users = new HashMap<>();
- protected List chats = new ArrayList<>();
- protected IDGenerator idGenerator;
- protected Cache messageCache = new Cache<>();
+ protected User user;
+ protected Map users = new HashMap<>();
+ protected List chats = new ArrayList<>();
+ protected IDGenerator idGenerator;
+ protected Cache messageCache = new Cache<>();
protected Cache statusCache = new Cache<>();
/**
@@ -66,6 +66,25 @@ public abstract class LocalDB {
*/
public void loadIDGenerator() {}
+ /**
+ * Synchronizes the contact list of the client user with the chat and user
+ * storage.
+ *
+ * @since Envoy Client v0.1-beta
+ */
+ public void synchronize() {
+ user.getContacts().stream().filter(u -> u instanceof User && !users.containsKey(u.getName())).forEach(u -> users.put(u.getName(), u));
+ users.put(user.getName(), user);
+
+ // Synchronize user status data
+ for (Contact contact : users.values())
+ if (contact instanceof User)
+ getChat(contact.getID()).ifPresent(chat -> { ((User) chat.getRecipient()).setStatus(((User) contact).getStatus()); });
+
+ // Create missing chats
+ user.getContacts().stream().filter(u -> !u.equals(user) && getChat(u.getID()).isEmpty()).map(Chat::new).forEach(chats::add);
+ }
+
/**
* @return a {@code Map} of all users stored locally with their
* user names as keys
@@ -73,11 +92,6 @@ public abstract class LocalDB {
*/
public Map getUsers() { return users; }
- /**
- * @param users the users to set
- */
- public void setUsers(Map users) { this.users = users; }
-
/**
* @return all saved {@link Chat} objects that list the client user as the
* sender
@@ -154,7 +168,7 @@ public abstract class LocalDB {
public Optional getMessage(long id) {
return chats.stream().map(Chat::getMessages).flatMap(List::stream).filter(m -> m.getID() == id).findAny();
}
-
+
/**
* Searches for a chat by recipient ID.
*
@@ -162,9 +176,7 @@ public abstract class LocalDB {
* @return an optional containing the chat
* @since Envoy Client v0.1-beta
*/
- public Optional getChat(long recipientID) {
- return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny();
- }
+ public Optional getChat(long recipientID) { return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny(); }
/**
* Performs a contact name change if the corresponding contact is present.
@@ -200,13 +212,4 @@ public abstract class LocalDB {
}
});
}
-
- /**
- * Creates a new {@link Chat} for all {@link Contact}s that do not have a chat.
- *
- * @since Envoy Client v0.1-beta
- */
- public void createMissingChats() {
- users.values().stream().filter(u -> !u.equals(user) && getChat(u.getID()).isEmpty()).map(Chat::new).forEach(chats::add);
- }
}
diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java
index 39052c1..34384ec 100644
--- a/src/main/java/envoy/client/net/Client.java
+++ b/src/main/java/envoy/client/net/Client.java
@@ -3,9 +3,6 @@ package envoy.client.net;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -42,9 +39,8 @@ public class Client implements Closeable {
private boolean online;
// Asynchronously initialized during handshake
- private volatile User sender;
- private volatile Set extends Contact> contacts;
- private volatile boolean rejected;
+ private volatile User sender;
+ private volatile boolean rejected;
// Configuration, logging and event management
private static final ClientConfig config = ClientConfig.getInstance();
@@ -73,9 +69,9 @@ public class Client implements Closeable {
* waiting for the handshake response
*/
public void performHandshake(LoginCredentials credentials, Cache receivedMessageCache,
- Cache receivedMessageStatusChangeCache)
- throws TimeoutException, IOException, InterruptedException {
+ Cache receivedMessageStatusChangeCache) throws TimeoutException, IOException, InterruptedException {
if (online) throw new IllegalStateException("Handshake has already been performed successfully");
+
// Establish TCP connection
logger.log(Level.FINER, String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort()));
socket = new Socket(config.getServer(), config.getPort());
@@ -85,7 +81,7 @@ public class Client implements Closeable {
receiver = new Receiver(socket.getInputStream());
// Register user creation processor, contact list processor and message cache
- receiver.registerProcessor(User.class, sender -> { this.sender = sender; contacts = sender.getContacts(); });
+ receiver.registerProcessor(User.class, sender -> this.sender = sender);
receiver.registerProcessor(Message.class, receivedMessageCache);
receiver.registerProcessor(MessageStatusChange.class, receivedMessageStatusChangeCache);
receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); });
@@ -142,12 +138,12 @@ public class Client implements Closeable {
* requested from the server
* @since Envoy Client v0.2-alpha
*/
- public void initReceiver(LocalDB localDB, Cache receivedMessageCache,
- Cache receivedMessageStatusChangeCache) throws IOException {
+ public void initReceiver(LocalDB localDB, Cache receivedMessageCache, Cache receivedMessageStatusChangeCache)
+ throws IOException {
checkOnline();
// Process incoming messages
- final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor();
+ final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor();
final MessageStatusChangeProcessor messageStatusChangeEventProcessor = new MessageStatusChangeProcessor();
receiver.registerProcessor(Message.class, receivedMessageProcessor);
@@ -182,8 +178,7 @@ public class Client implements Closeable {
try {
sendEvent(evt.get());
} catch (final IOException e) {
- e.printStackTrace();
- logger.log(Level.WARNING, "An error occurred when trying to send Event " + evt, e);
+ logger.log(Level.WARNING, "An error occurred when trying to send " + evt, e);
}
});
@@ -234,19 +229,6 @@ public class Client implements Closeable {
writeObject(new IDGeneratorRequest());
}
- /**
- * @return a {@code Map} of all users on the server with their
- * user names as keys
- * @since Envoy Client v0.2-alpha
- */
- public Map getUsers() {
- checkOnline();
- final Map users = new HashMap<>();
- contacts.forEach(u -> users.put(u.getName(), u));
- users.put(sender.getName(), sender);
- return users;
- }
-
@Override
public void close() throws IOException { if (online) socket.close(); }
@@ -259,7 +241,7 @@ public class Client implements Closeable {
private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); }
/**
- * @return the sender object that represents this client.
+ * @return the {@link User} as which this client is logged in
* @since Envoy Client v0.1-alpha
*/
public User getSender() { return sender; }
@@ -282,16 +264,4 @@ public class Client implements Closeable {
* @since Envoy Client v0.2-alpha
*/
public boolean isOnline() { return online; }
-
- /**
- * @return the contacts of this {@link Client}
- * @since Envoy Client v0.3-alpha
- */
- public Set extends Contact> getContacts() { return contacts; }
-
- /**
- * @param contacts the contacts to set
- * @since Envoy Client v0.3-alpha
- */
- public void setContacts(Set extends Contact> contacts) { this.contacts = contacts; }
}
diff --git a/src/main/java/envoy/client/net/Receiver.java b/src/main/java/envoy/client/net/Receiver.java
index 55042d3..c71e5ed 100644
--- a/src/main/java/envoy/client/net/Receiver.java
+++ b/src/main/java/envoy/client/net/Receiver.java
@@ -79,7 +79,6 @@ public class Receiver extends Thread {
// Connection probably closed by client.
} catch (final Exception e) {
logger.log(Level.SEVERE, "Error on receiver thread", e);
- e.printStackTrace();
}
}
diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java
index 2287369..90e49e0 100644
--- a/src/main/java/envoy/client/net/WriteProxy.java
+++ b/src/main/java/envoy/client/net/WriteProxy.java
@@ -47,9 +47,6 @@ public class WriteProxy {
try {
logger.log(Level.FINER, "Sending cached " + msg);
client.sendMessage(msg);
-
- // Update message state to SENT in localDB
- localDB.getMessage(msg.getID()).ifPresent(Message::nextStatus);
} catch (final IOException e) {
logger.log(Level.SEVERE, "Could not send cached message: ", e);
}
diff --git a/src/main/java/envoy/client/ui/controller/ChatScene.java b/src/main/java/envoy/client/ui/controller/ChatScene.java
index cd58ecb..ff93351 100644
--- a/src/main/java/envoy/client/ui/controller/ChatScene.java
+++ b/src/main/java/envoy/client/ui/controller/ChatScene.java
@@ -164,13 +164,13 @@ public final class ChatScene {
private void userListClicked() {
final Contact user = userList.getSelectionModel().getSelectedItem();
if (user != null && (currentChat == null || !user.equals(currentChat.getRecipient()))) {
+ logger.log(Level.FINEST, "Loading chat with " + user);
contactLabel.setText(user.getName());
// LEON: JFC <===> JAVA FRIED CHICKEN <=/=> Java Foundation Classes
- // Load the chat or create a new one and add it to the LocalDB
- currentChat = localDB.getChat(user.getID())
- .orElseGet(() -> { final var chat = new Chat(user); localDB.getChats().add(chat); return chat; });
+ // Load the chat
+ currentChat = localDB.getChat(user.getID()).get();
messageList.setItems(FXCollections.observableList(currentChat.getMessages()));
diff --git a/src/main/java/envoy/client/ui/controller/LoginScene.java b/src/main/java/envoy/client/ui/controller/LoginScene.java
index a72ef78..b17fa81 100644
--- a/src/main/java/envoy/client/ui/controller/LoginScene.java
+++ b/src/main/java/envoy/client/ui/controller/LoginScene.java
@@ -11,9 +11,7 @@ import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
-import envoy.client.data.Cache;
-import envoy.client.data.ClientConfig;
-import envoy.client.data.LocalDB;
+import envoy.client.data.*;
import envoy.client.net.Client;
import envoy.client.ui.SceneContext;
import envoy.client.ui.Startup;
@@ -183,7 +181,6 @@ public final class LoginScene {
} catch (final FileNotFoundException e) {
// The local database file has not yet been created, probably first login
} catch (final Exception e) {
- e.printStackTrace();
new Alert(AlertType.ERROR, "Error while loading local database: " + e + "\nChats will not be stored locally.").showAndWait();
logger.log(Level.WARNING, "Could not load local database: ", e);
}
@@ -191,15 +188,18 @@ public final class LoginScene {
// Initialize write proxy
final var writeProxy = client.createWriteProxy(localDB);
- if (client.isOnline()) {
+ localDB.synchronize();
- // Save all users to the local database and flush cache
- localDB.setUsers(client.getUsers());
- localDB.createMissingChats();
+ if (client.isOnline()) {
writeProxy.flushCache();
} else
// Set all contacts to offline mode
- localDB.getUsers().values().stream().filter(User.class::isInstance).map(User.class::cast).forEach(u -> u.setStatus(UserStatus.OFFLINE));
+ localDB.getChats()
+ .stream()
+ .map(Chat::getRecipient)
+ .filter(User.class::isInstance)
+ .map(User.class::cast)
+ .forEach(u -> u.setStatus(UserStatus.OFFLINE));
// Load ChatScene
sceneContext.pop();