diff --git a/src/main/java/envoy/client/data/Cache.java b/src/main/java/envoy/client/data/Cache.java index 366f703..458cb0a 100644 --- a/src/main/java/envoy/client/data/Cache.java +++ b/src/main/java/envoy/client/data/Cache.java @@ -20,8 +20,8 @@ import envoy.client.util.EnvoyLog; */ public class Cache implements Consumer { - private final Queue elements = new LinkedList<>(); - private Consumer processor; + private final Queue elements = new LinkedList<>(); + private transient Consumer processor; private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName()); @@ -54,5 +54,6 @@ public class Cache implements Consumer { public void relay() { if (processor == null) throw new IllegalStateException("Processor is not defined"); elements.forEach(processor::accept); + elements.clear(); } } diff --git a/src/main/java/envoy/client/data/LocalDb.java b/src/main/java/envoy/client/data/LocalDb.java index 79368a8..a606856 100644 --- a/src/main/java/envoy/client/data/LocalDb.java +++ b/src/main/java/envoy/client/data/LocalDb.java @@ -3,7 +3,9 @@ package envoy.client.data; import java.util.*; import envoy.data.IdGenerator; +import envoy.data.Message; import envoy.data.User; +import envoy.event.MessageStatusChangeEvent; /** * Stores information about the current {@link User} and their {@link Chat}s. @@ -18,10 +20,12 @@ import envoy.data.User; */ public abstract class LocalDb { - protected User user; - protected Map users = new HashMap<>(); - protected List chats = new ArrayList<>(); - protected IdGenerator idGenerator; + protected User user; + protected Map users = new HashMap<>(); + protected List chats = new ArrayList<>(); + protected IdGenerator idGenerator; + protected Cache messageCache; + protected Cache statusCache; /** * Initializes a storage space for a user-specific list of chats. @@ -115,4 +119,28 @@ public abstract class LocalDb { * @since Envoy v0.3-alpha */ public boolean hasIdGenerator() { return idGenerator != null; } + + /** + * @return the offline message cache + * @since Envoy v0.3-alpha + */ + public Cache getMessageCache() { return messageCache; } + + /** + * @param messageCache the offline message cache to set + * @since Envoy v0.3-alpha + */ + public void setMessageCache(Cache messageCache) { this.messageCache = messageCache; } + + /** + * @return the offline status cache + * @since Envoy v0.3-alpha + */ + public Cache getStatusCache() { return statusCache; } + + /** + * @param statusCache the offline status cache to set + * @since Envoy v0.3-alpha + */ + public void setStatusCache(Cache statusCache) { this.statusCache = statusCache; } } diff --git a/src/main/java/envoy/client/data/PersistentLocalDb.java b/src/main/java/envoy/client/data/PersistentLocalDb.java index 7856517..7052c60 100644 --- a/src/main/java/envoy/client/data/PersistentLocalDb.java +++ b/src/main/java/envoy/client/data/PersistentLocalDb.java @@ -40,18 +40,18 @@ public class PersistentLocalDb extends LocalDb { * Constructs an empty local database. To serialize any chats to the file * system, call {@link PersistentLocalDb#initializeUserStorage()}. * - * @param localDBDir the directory in which to store users and chats + * @param localDbDir the directory in which to store users and chats * @throws IOException if the PersistentLocalDb could not be initialized * @since Envoy v0.1-alpha */ - public PersistentLocalDb(File localDBDir) throws IOException { - this.localDBDir = localDBDir; + public PersistentLocalDb(File localDbDir) throws IOException { + localDBDir = localDbDir; // Initialize local database directory - if (localDBDir.exists() && !localDBDir.isDirectory()) - throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); - usersFile = new File(localDBDir, "users.db"); - idGeneratorFile = new File(localDBDir, "id_generator.db"); + if (localDbDir.exists() && !localDbDir.isDirectory()) + throw new IOException(String.format("LocalDbDir '%s' is not a directory!", localDbDir.getAbsolutePath())); + usersFile = new File(localDbDir, "users.db"); + idGeneratorFile = new File(localDbDir, "id_generator.db"); } /** diff --git a/src/main/java/envoy/client/net/Client.java b/src/main/java/envoy/client/net/Client.java index 2e96b4a..29b2f03 100644 --- a/src/main/java/envoy/client/net/Client.java +++ b/src/main/java/envoy/client/net/Client.java @@ -118,6 +118,17 @@ public class Client implements Closeable { return cache; } + /** + * Creates a new write proxy that uses this client to communicate with the + * server. + * + * @param localDb the local database that the write proxy will use to access + * caches + * @return a new write proxy + * @since Envoy Client v0.3-alpha + */ + public WriteProxy createWriteProxy(LocalDb localDb) { return new WriteProxy(this, localDb); } + /** * Sends a message to the server. The message's status will be incremented once * it was delivered successfully. diff --git a/src/main/java/envoy/client/net/WriteProxy.java b/src/main/java/envoy/client/net/WriteProxy.java new file mode 100644 index 0000000..454751f --- /dev/null +++ b/src/main/java/envoy/client/net/WriteProxy.java @@ -0,0 +1,102 @@ +package envoy.client.net; + +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; + +import envoy.client.data.LocalDb; +import envoy.client.util.EnvoyLog; +import envoy.data.Message; +import envoy.event.MessageStatusChangeEvent; + +/** + * Implements methods to send {@link Message}s and + * {@link MessageStatusChangeEvent}s to the server or cache them inside a + * {@link LocalDb} depending on the online status.
+ *
+ * Project: envoy-client
+ * File: WriteProxy.java
+ * Created: 6 Feb 2020
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.3-alpha + */ +public class WriteProxy { + + private final Client client; + private final LocalDb localDb; + + private static final Logger logger = EnvoyLog.getLogger(WriteProxy.class.getSimpleName()); + + /** + * Initializes a write proxy using a client and a local database. The + * corresponding cache processors are injected into the caches. + * + * @param client the client used to send messages and message status change + * events + * @param localDb the local database used to cache messages and message status + * change events + * @since Envoy v0.3-alpha + */ + public WriteProxy(Client client, LocalDb localDb) { + this.client = client; + this.localDb = localDb; + + // Initialize cache processors for messages and message status change events + localDb.getMessageCache().setProcessor(msg -> { + try { + client.sendMessage(msg); + } catch (IOException e) { + logger.log(Level.SEVERE, "Could not send cached message", e); + } + }); + localDb.getStatusCache().setProcessor(evt -> { + try { + client.sendEvent(evt); + } catch (IOException e) { + logger.log(Level.SEVERE, "Could not send cached message status change event", e); + } + }); + } + + /** + * Sends cached {@link Message}s and {@link MessageStatusChangeEvent}s to the + * server. + * + * @since Envoy v0.3-alpha + */ + public void flushCache() { + + // Send messages + localDb.getMessageCache().relay(); + + // Send message status change events + localDb.getStatusCache().relay(); + } + + /** + * Delivers a message to the server if online. Otherwise the message is cached + * inside the local database. + * + * @param message the message to send + * @throws IOException if the message could not be sent + * @since Envoy v0.3-alpha + */ + public void writeMessage(Message message) throws IOException { + if (client.isOnline()) client.sendMessage(message); + else localDb.getMessageCache().accept(message); + } + + /** + * Delivers a message status change event to the server if online. Otherwise the + * event is cached inside the local database. + * + * @param evt the event to send + * @throws IOException if the event could not be sent + * @since Envoy v0.3-alpha + */ + public void writeMessageStatusChangeEvent(MessageStatusChangeEvent evt) throws IOException { + if (client.isOnline()) client.sendEvent(evt); + else localDb.getStatusCache().accept(evt); + } +}