Simplify cache storage with a CacheMap class

This commit is contained in:
Kai S. K. Engelbart 2020-07-09 09:37:31 +02:00
parent 4f654cc2a5
commit 9c19d544d6
5 changed files with 74 additions and 28 deletions

View File

@ -0,0 +1,46 @@
package envoy.client.data;
import java.util.HashMap;
import java.util.Map;
/**
* Stores a heterogeneous map of {@link Cache} objects with different type
* parameters.
* <p>
* Project: <strong>envoy-client</strong><br>
* File: <strong>CacheMap.java</strong><br>
* Created: <strong>09.07.2020</strong><br>
*
* @author Kai S. K. Engelbart
* @since Envoy Client v0.1-beta
*/
public final class CacheMap {
private final Map<Class<?>, Cache<?>> map = new HashMap<>();
/**
* Adds a cache to the map.
*
* @param <T> the type accepted by the cache
* @param key the class that maps to the cache
* @param cache the cache to store
* @since Envoy Client v0.1-beta
*/
public <T> void put(Class<T> key, Cache<T> cache) { map.put(key, cache); }
/**
* Returns a cache mapped by a class.
*
* @param <T> the type accepted by the cache
* @param key the class that maps to the cache
* @return the cache
* @since Envoy Client v0.1-beta
*/
public <T> Cache<T> get(Class<T> key) { return (Cache<T>) map.get(key); }
/**
* @return the map in which the caches are stored
* @since Envoy Client v0.1-beta
*/
public Map<Class<?>, Cache<?>> getMap() { return map; }
}

View File

@ -3,13 +3,11 @@ package envoy.client.net;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.util.Map;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import envoy.client.data.Cache; import envoy.client.data.CacheMap;
import envoy.client.data.ClientConfig; import envoy.client.data.ClientConfig;
import envoy.client.data.LocalDB; import envoy.client.data.LocalDB;
import envoy.client.event.SendEvent; import envoy.client.event.SendEvent;
@ -40,8 +38,6 @@ public class Client implements Closeable {
private Receiver receiver; private Receiver receiver;
private boolean online; private boolean online;
private Map<Class<?>, Cache<?>> cacheMap;
// Asynchronously initialized during handshake // Asynchronously initialized during handshake
private volatile User sender; private volatile User sender;
private volatile boolean rejected; private volatile boolean rejected;
@ -64,7 +60,8 @@ public class Client implements Closeable {
* @throws InterruptedException if the current thread is interrupted while * @throws InterruptedException if the current thread is interrupted while
* waiting for the handshake response * waiting for the handshake response
*/ */
public void performHandshake(LoginCredentials credentials, Map<Class<?>, Cache<?>> cacheMap) public void performHandshake(LoginCredentials credentials,
CacheMap cacheMap)
throws TimeoutException, IOException, InterruptedException { throws TimeoutException, IOException, InterruptedException {
if (online) throw new IllegalStateException("Handshake has already been performed successfully"); if (online) throw new IllegalStateException("Handshake has already been performed successfully");
@ -78,7 +75,7 @@ public class Client implements Closeable {
// Register user creation processor, contact list processor and message cache // Register user creation processor, contact list processor and message cache
receiver.registerProcessor(User.class, sender -> this.sender = sender); receiver.registerProcessor(User.class, sender -> this.sender = sender);
cacheMap.forEach((inputclass, cache) -> receiver.registerProcessor(inputclass, cache)); receiver.registerProcessors(cacheMap.getMap());
receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); }); receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); });
rejected = false; rejected = false;
@ -124,7 +121,7 @@ public class Client implements Closeable {
* requested from the server * requested from the server
* @since Envoy Client v0.2-alpha * @since Envoy Client v0.2-alpha
*/ */
public void initReceiver(LocalDB localDB, Map<Class<?>, Cache<?>> cacheMap) throws IOException { public void initReceiver(LocalDB localDB, CacheMap cacheMap) throws IOException {
checkOnline(); checkOnline();
// Process incoming messages // Process incoming messages
@ -134,18 +131,17 @@ public class Client implements Closeable {
final GroupMessageStatusChangeProcessor groupMessageStatusChangeProcessor = new GroupMessageStatusChangeProcessor(); final GroupMessageStatusChangeProcessor groupMessageStatusChangeProcessor = new GroupMessageStatusChangeProcessor();
receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor); receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor);
receiver.registerProcessor(Message.class, receivedMessageProcessor); receiver.registerProcessor(Message.class, receivedMessageProcessor);
receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor); receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor);
receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor); receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor);
// Relay cached unread messages and unread groupMessages // Relay cached unread messages and unread groupMessages
cacheMap.get(Message.class).setProcessor((Consumer<?>) receivedMessageProcessor); cacheMap.get(Message.class).setProcessor(receivedMessageProcessor);
cacheMap.get(GroupMessage.class).setProcessor((Consumer<?>) receivedGroupMessageProcessor); cacheMap.get(GroupMessage.class).setProcessor(receivedGroupMessageProcessor);
// Process message status changes
cacheMap.get(MessageStatusChange.class).setProcessor((Consumer<?>) messageStatusChangeProcessor); // Relay cached status changes
cacheMap.get(GroupMessageStatusChange.class).setProcessor((Consumer<?>) groupMessageStatusChangeProcessor); cacheMap.get(MessageStatusChange.class).setProcessor(messageStatusChangeProcessor);
cacheMap.get(GroupMessageStatusChange.class).setProcessor(groupMessageStatusChangeProcessor);
// Process user status changes // Process user status changes
receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch); receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch);

View File

@ -79,9 +79,7 @@ public class Receiver extends Thread {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
final Consumer processor = processors.get(obj.getClass()); final Consumer processor = processors.get(obj.getClass());
if (processor == null) if (processor == null)
logger.log(Level.WARNING, String.format( logger.log(Level.WARNING, String.format("The received object has the %s for which no processor is defined.", obj.getClass()));
"The received object has the %s for which no processor is defined.",
obj.getClass()));
else processor.accept(obj); else processor.accept(obj);
} }
} catch (final SocketException e) { } catch (final SocketException e) {
@ -103,6 +101,14 @@ public class Receiver extends Thread {
*/ */
public <T> void registerProcessor(Class<T> processorClass, Consumer<T> processor) { processors.put(processorClass, processor); } public <T> void registerProcessor(Class<T> processorClass, Consumer<T> processor) { processors.put(processorClass, processor); }
/**
* Adds a map of object processors to this {@link Receiver}.
*
* @param processors the processors to add the processors to add
* @since Envoy Client v0.1-beta
*/
public void registerProcessors(Map<Class<?>, ? extends Consumer<?>> processors) { this.processors.putAll(processors); }
/** /**
* Removes all object processors registered at this {@link Receiver}. * Removes all object processors registered at this {@link Receiver}.
* *

View File

@ -2,7 +2,6 @@ package envoy.client.ui;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Properties; import java.util.Properties;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -100,7 +99,7 @@ public final class Startup extends Application {
// Initialize client and unread message cache // Initialize client and unread message cache
client = new Client(); client = new Client();
final var cacheMap = new HashMap<Class<?>, Cache<?>>(); final var cacheMap = new CacheMap();
cacheMap.put(Message.class, new Cache<Message>()); cacheMap.put(Message.class, new Cache<Message>());
cacheMap.put(GroupMessage.class, new Cache<GroupMessage>()); cacheMap.put(GroupMessage.class, new Cache<GroupMessage>());
cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>()); cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>());

View File

@ -2,7 +2,6 @@ package envoy.client.ui.controller;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -55,10 +54,10 @@ public final class LoginScene {
@FXML @FXML
private Label connectionLabel; private Label connectionLabel;
private Client client; private Client client;
private LocalDB localDB; private LocalDB localDB;
private Map<Class<?>, Cache<?>> cacheMap; private CacheMap cacheMap;
private SceneContext sceneContext; private SceneContext sceneContext;
private static final Logger logger = EnvoyLog.getLogger(LoginScene.class); private static final Logger logger = EnvoyLog.getLogger(LoginScene.class);
private static final EventBus eventBus = EventBus.getInstance(); private static final EventBus eventBus = EventBus.getInstance();
@ -81,7 +80,7 @@ public final class LoginScene {
* @param sceneContext the scene context used to initialize the chat scene * @param sceneContext the scene context used to initialize the chat scene
* @since Envoy Client v0.1-beta * @since Envoy Client v0.1-beta
*/ */
public void initializeData(Client client, LocalDB localDB, Map<Class<?>, Cache<?>> cacheMap, SceneContext sceneContext) { public void initializeData(Client client, LocalDB localDB, CacheMap cacheMap, SceneContext sceneContext) {
this.client = client; this.client = client;
this.localDB = localDB; this.localDB = localDB;
this.cacheMap = cacheMap; this.cacheMap = cacheMap;
@ -198,6 +197,6 @@ public final class LoginScene {
sceneContext.<ChatScene>getController().initializeData(sceneContext, localDB, client, writeProxy); sceneContext.<ChatScene>getController().initializeData(sceneContext, localDB, client, writeProxy);
// Relay unread messages from cache // Relay unread messages from cache
if (client.isOnline()) cacheMap.values().forEach(cache -> { if (cache != null) cache.relay(); }); if (client.isOnline()) cacheMap.getMap().values().forEach(cache -> { if (cache != null) cache.relay(); });
} }
} }