Merge branch 'develop' into f/contacts
This commit is contained in:
commit
84fb28cb34
25
pom.xml
25
pom.xml
@ -39,5 +39,30 @@
|
|||||||
<directory>src/main/resources</directory>
|
<directory>src/main/resources</directory>
|
||||||
</resource>
|
</resource>
|
||||||
</resources>
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>2.4.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>envoy.client.ui.Startup</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
@ -6,6 +6,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
import envoy.client.data.Config;
|
||||||
import envoy.client.ui.Color;
|
import envoy.client.ui.Color;
|
||||||
import envoy.client.ui.Theme;
|
import envoy.client.ui.Theme;
|
||||||
import envoy.util.SerializationUtils;
|
import envoy.util.SerializationUtils;
|
||||||
|
61
src/main/java/envoy/client/data/Cache.java
Normal file
61
src/main/java/envoy/client/data/Cache.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package envoy.client.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import envoy.client.util.EnvoyLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores elements in a queue to process them later.<br>
|
||||||
|
* <br>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>Cache.java</strong><br>
|
||||||
|
* Created: <strong>6 Feb 2020</strong><br>
|
||||||
|
*
|
||||||
|
* @param <T> the type of cached elements
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public class Cache<T> implements Consumer<T>, Serializable {
|
||||||
|
|
||||||
|
private final Queue<T> elements = new LinkedList<>();
|
||||||
|
private transient Consumer<T> processor;
|
||||||
|
|
||||||
|
private static final Logger logger = EnvoyLog.getLogger(Cache.class.getSimpleName());
|
||||||
|
private static final long serialVersionUID = 7343544675545545076L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an element to the cache.
|
||||||
|
*
|
||||||
|
* @param element the element to add
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void accept(T element) {
|
||||||
|
logger.info(String.format("Adding element %s to cache", element));
|
||||||
|
elements.offer(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processor to which cached elements are relayed.
|
||||||
|
*
|
||||||
|
* @param processor the processor to set
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public void setProcessor(Consumer<T> processor) { this.processor = processor; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relays all cached elements to the processor.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if the processor is not initialized
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public void relay() {
|
||||||
|
if (processor == null) throw new IllegalStateException("Processor is not defined");
|
||||||
|
elements.forEach(processor::accept);
|
||||||
|
elements.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ package envoy.client.data;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import envoy.client.net.Client;
|
import envoy.client.net.WriteProxy;
|
||||||
import envoy.client.ui.list.ComponentListModel;
|
import envoy.client.ui.list.ComponentListModel;
|
||||||
import envoy.data.Message;
|
import envoy.data.Message;
|
||||||
import envoy.data.Message.MessageStatus;
|
import envoy.data.Message.MessageStatus;
|
||||||
@ -52,22 +52,20 @@ public class Chat implements Serializable {
|
|||||||
* {@code READ} starting from the bottom and stopping once a read message is
|
* {@code READ} starting from the bottom and stopping once a read message is
|
||||||
* found.
|
* found.
|
||||||
*
|
*
|
||||||
* @param client the client instance used to notify the server about the message
|
* @param writeProxy the write proxy instance used to notify the server about
|
||||||
* status changes
|
* the message status changes
|
||||||
* @throws IOException if a {@link MessageStatusChangeEvent} could not be
|
* @throws IOException if a {@link MessageStatusChangeEvent} could not be
|
||||||
* delivered to the server
|
* delivered to the server
|
||||||
* @since Envoy v0.3-alpha
|
* @since Envoy v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public void read(Client client) throws IOException {
|
public void read(WriteProxy writeProxy) throws IOException {
|
||||||
for (int i = model.size() - 1; i >= 0; --i) {
|
for (int i = model.size() - 1; i >= 0; --i) {
|
||||||
final Message m = model.get(i);
|
final Message m = model.get(i);
|
||||||
if (m.getSenderId() == recipient.getId()) {
|
if (m.getSenderId() == recipient.getId()) {
|
||||||
if (m.getStatus() == MessageStatus.READ) break;
|
if (m.getStatus() == MessageStatus.READ) break;
|
||||||
else {
|
else {
|
||||||
m.setStatus(MessageStatus.READ);
|
m.setStatus(MessageStatus.READ);
|
||||||
|
writeProxy.writeMessageStatusChangeEvent(new MessageStatusChangeEvent(m));
|
||||||
// TODO: Cache events in offline mode
|
|
||||||
client.sendEvent(new MessageStatusChangeEvent(m));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package envoy.client;
|
package envoy.client.data;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import envoy.data.LoginCredentials;
|
||||||
import envoy.exception.EnvoyException;
|
import envoy.exception.EnvoyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,14 +29,15 @@ public class Config {
|
|||||||
private static Config config;
|
private static Config config;
|
||||||
|
|
||||||
private Config() {
|
private Config() {
|
||||||
items.put("server", new ConfigItem<>("server", "s", (input) -> input, null));
|
items.put("server", new ConfigItem<>("server", "s", Function.identity(), null, true));
|
||||||
items.put("port", new ConfigItem<>("port", "p", (input) -> Integer.parseInt(input), null));
|
items.put("port", new ConfigItem<>("port", "p", Integer::parseInt, null, true));
|
||||||
items.put("localDB", new ConfigItem<>("localDB", "db", (input) -> new File(input), new File("localDB")));
|
items.put("localDB", new ConfigItem<>("localDB", "db", File::new, new File("localDB"), true));
|
||||||
items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", (input) -> Boolean.parseBoolean(input), false));
|
items.put("ignoreLocalDB", new ConfigItem<>("ignoreLocalDB", "nodb", Boolean::parseBoolean, false, false));
|
||||||
items.put("homeDirectory",
|
items.put("homeDirectory", new ConfigItem<>("homeDirectory", "h", File::new, new File(System.getProperty("user.home"), ".envoy"), true));
|
||||||
new ConfigItem<>("homeDirectory", "h", (input) -> new File(input), new File(System.getProperty("user.home"), ".envoy")));
|
items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", Level::parse, Level.CONFIG, true));
|
||||||
items.put("fileLevelBarrier", new ConfigItem<>("fileLevelBarrier", "fb", (input) -> Level.parse(input), Level.CONFIG));
|
items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", Level::parse, Level.FINEST, true));
|
||||||
items.put("consoleLevelBarrier", new ConfigItem<>("consoleLevelBarrier", "cb", (input) -> Level.parse(input), Level.FINEST));
|
items.put("user", new ConfigItem<>("user", "u", Function.identity()));
|
||||||
|
items.put("password", new ConfigItem<>("password", "pw", String::toCharArray));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,10 +99,12 @@ public class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@code true} if server, port and localDB directory are known.
|
* @return {@code true} if all mandatory config items are initialized
|
||||||
* @since Envoy v0.1-alpha
|
* @since Envoy v0.1-alpha
|
||||||
*/
|
*/
|
||||||
public boolean isInitialized() { return items.values().stream().map(ConfigItem::get).noneMatch(Objects::isNull); }
|
public boolean isInitialized() {
|
||||||
|
return items.values().stream().filter(ConfigItem::isMandatory).map(ConfigItem::get).noneMatch(Objects::isNull);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the host name of the Envoy server
|
* @return the host name of the Envoy server
|
||||||
@ -141,4 +147,35 @@ public class Config {
|
|||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); }
|
public Level getConsoleLevelBarrier() { return (Level) items.get("consoleLevelBarrier").get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the user name
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public String getUser() { return (String) items.get("user").get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the password
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public char[] getPassword() { return (char[]) items.get("password").get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if user name and password are set
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public boolean hasLoginCredentials() { return getUser() != null && getPassword() != null; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return login credentials for the specified user name and password, without
|
||||||
|
* the registration option
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public LoginCredentials getLoginCredentials() {
|
||||||
|
try {
|
||||||
|
return new LoginCredentials(getUser(), getPassword(), false);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package envoy.client;
|
package envoy.client.data;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@ -9,49 +9,70 @@ import java.util.function.Function;
|
|||||||
* Project: <strong>envoy-clientChess</strong><br>
|
* Project: <strong>envoy-clientChess</strong><br>
|
||||||
* File: <strong>ConfigItem.javaEvent.java</strong><br>
|
* File: <strong>ConfigItem.javaEvent.java</strong><br>
|
||||||
* Created: <strong>21.12.2019</strong><br>
|
* Created: <strong>21.12.2019</strong><br>
|
||||||
*
|
*
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
* @param <T> the type of the config item's value
|
* @param <T> the type of the config item's value
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public class ConfigItem<T> {
|
public class ConfigItem<T> {
|
||||||
|
|
||||||
private String commandLong, commandShort;
|
private final String commandLong, commandShort;
|
||||||
private Function<String, T> parseFunction;
|
private final Function<String, T> parseFunction;
|
||||||
private T value;
|
private final boolean mandatory;
|
||||||
|
|
||||||
|
private T value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a {@link ConfigItem}
|
* Initializes a {@link ConfigItem}.
|
||||||
*
|
*
|
||||||
* @param commandLong the long command line argument to set this value
|
* @param commandLong the long command line argument to set this value
|
||||||
* @param commandShort the short command line argument to set this value
|
* @param commandShort the short command line argument to set this value
|
||||||
* @param parseFunction the {@code Function<String, T>} that parses the value
|
* @param parseFunction the {@code Function<String, T>} that parses the value
|
||||||
* from a string
|
* from a string
|
||||||
* @param defaultValue the optional default value to set before parsing
|
* @param defaultValue the optional default value to set before parsing
|
||||||
|
* @param mandatory indicated that this config item must be initialized with
|
||||||
|
* a non-null value
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public ConfigItem(String commandLong, String commandShort, Function<String, T> parseFunction, T defaultValue) {
|
public ConfigItem(String commandLong, String commandShort, Function<String, T> parseFunction, T defaultValue, boolean mandatory) {
|
||||||
this.commandLong = commandLong;
|
this.commandLong = commandLong;
|
||||||
this.commandShort = commandShort;
|
this.commandShort = commandShort;
|
||||||
this.parseFunction = parseFunction;
|
this.parseFunction = parseFunction;
|
||||||
|
this.mandatory = mandatory;
|
||||||
value = defaultValue;
|
value = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses this {@ConfigItem}'s value from a string
|
* Initializes an optional {@link ConfigItem} without a default value.
|
||||||
|
*
|
||||||
|
* @param commandLong the long command line argument to set this value
|
||||||
|
* @param commandShort the short command line argument to set this value
|
||||||
|
* @param parseFunction the {@code Function<String, T>} that parses the value
|
||||||
|
* from a string
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public ConfigItem(String commandLong, String commandShort, Function<String, T> parseFunction) {
|
||||||
|
this(commandLong, commandShort, parseFunction, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses this {@ConfigItem}'s value from a string.
|
||||||
|
*
|
||||||
* @param input the string to parse from
|
* @param input the string to parse from
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public void parse(String input) { value = parseFunction.apply(input); }
|
public void parse(String input) { value = parseFunction.apply(input); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The long command line argument to set the value of this {@link ConfigItem}
|
* @return The long command line argument to set the value of this
|
||||||
|
* {@link ConfigItem}
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public String getCommandLong() { return commandLong; }
|
public String getCommandLong() { return commandLong; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The short command line argument to set the value of this {@link ConfigItem}
|
* @return The short command line argument to set the value of this
|
||||||
|
* {@link ConfigItem}
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public String getCommandShort() { return commandShort; }
|
public String getCommandShort() { return commandShort; }
|
||||||
@ -61,4 +82,11 @@ public class ConfigItem<T> {
|
|||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public T get() { return value; }
|
public T get() { return value; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if this {@link ConfigItem} is mandatory for successful
|
||||||
|
* application initialization
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public boolean isMandatory() { return mandatory; }
|
||||||
}
|
}
|
@ -3,7 +3,9 @@ package envoy.client.data;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import envoy.data.IdGenerator;
|
import envoy.data.IdGenerator;
|
||||||
|
import envoy.data.Message;
|
||||||
import envoy.data.User;
|
import envoy.data.User;
|
||||||
|
import envoy.event.MessageStatusChangeEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores information about the current {@link User} and their {@link Chat}s.
|
* Stores information about the current {@link User} and their {@link Chat}s.
|
||||||
@ -18,10 +20,12 @@ import envoy.data.User;
|
|||||||
*/
|
*/
|
||||||
public abstract class LocalDb {
|
public abstract class LocalDb {
|
||||||
|
|
||||||
protected User user;
|
protected User user;
|
||||||
protected Map<String, User> users = new HashMap<>();
|
protected Map<String, User> users = new HashMap<>();
|
||||||
protected List<Chat> chats = new ArrayList<>();
|
protected List<Chat> chats = new ArrayList<>();
|
||||||
protected IdGenerator idGenerator;
|
protected IdGenerator idGenerator;
|
||||||
|
protected Cache<Message> messageCache = new Cache<>();
|
||||||
|
protected Cache<MessageStatusChangeEvent> statusCache = new Cache<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a storage space for a user-specific list of chats.
|
* Initializes a storage space for a user-specific list of chats.
|
||||||
@ -48,12 +52,12 @@ public abstract class LocalDb {
|
|||||||
public void loadUsers() throws Exception {}
|
public void loadUsers() throws Exception {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all chat data of the client user.
|
* Loads all data of the client user.
|
||||||
*
|
*
|
||||||
* @throws Exception if the loading process failed
|
* @throws Exception if the loading process failed
|
||||||
* @since Envoy v0.3-alpha
|
* @since Envoy v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public void loadChats() throws Exception {}
|
public void loadUserData() throws Exception {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the ID generator. Any exception thrown during this process is ignored.
|
* Loads the ID generator. Any exception thrown during this process is ignored.
|
||||||
@ -115,4 +119,28 @@ public abstract class LocalDb {
|
|||||||
* @since Envoy v0.3-alpha
|
* @since Envoy v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public boolean hasIdGenerator() { return idGenerator != null; }
|
public boolean hasIdGenerator() { return idGenerator != null; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the offline message cache
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public Cache<Message> getMessageCache() { return messageCache; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param messageCache the offline message cache to set
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public void setMessageCache(Cache<Message> messageCache) { this.messageCache = messageCache; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the offline status cache
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public Cache<MessageStatusChangeEvent> getStatusCache() { return statusCache; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statusCache the offline status cache to set
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public void setStatusCache(Cache<MessageStatusChangeEvent> statusCache) { this.statusCache = statusCache; }
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import java.io.IOException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import envoy.client.ConfigItem;
|
|
||||||
import envoy.data.IdGenerator;
|
import envoy.data.IdGenerator;
|
||||||
import envoy.util.SerializationUtils;
|
import envoy.util.SerializationUtils;
|
||||||
|
|
||||||
@ -23,7 +22,7 @@ import envoy.util.SerializationUtils;
|
|||||||
*/
|
*/
|
||||||
public class PersistentLocalDb extends LocalDb {
|
public class PersistentLocalDb extends LocalDb {
|
||||||
|
|
||||||
private File localDBDir, localDBFile, usersFile, idGeneratorFile;
|
private File localDBDir, localDBFile, usersFile, idGeneratorFile, messageCacheFile, statusCacheFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an empty local database without a directory. All changes made to
|
* Initializes an empty local database without a directory. All changes made to
|
||||||
@ -40,18 +39,18 @@ public class PersistentLocalDb extends LocalDb {
|
|||||||
* Constructs an empty local database. To serialize any chats to the file
|
* Constructs an empty local database. To serialize any chats to the file
|
||||||
* system, call {@link PersistentLocalDb#initializeUserStorage()}.
|
* 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
|
* @throws IOException if the PersistentLocalDb could not be initialized
|
||||||
* @since Envoy v0.1-alpha
|
* @since Envoy v0.1-alpha
|
||||||
*/
|
*/
|
||||||
public PersistentLocalDb(File localDBDir) throws IOException {
|
public PersistentLocalDb(File localDbDir) throws IOException {
|
||||||
this.localDBDir = localDBDir;
|
localDBDir = localDbDir;
|
||||||
|
|
||||||
// Initialize local database directory
|
// Initialize local database directory
|
||||||
if (localDBDir.exists() && !localDBDir.isDirectory())
|
if (localDbDir.exists() && !localDbDir.isDirectory())
|
||||||
throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath()));
|
throw new IOException(String.format("LocalDbDir '%s' is not a directory!", localDbDir.getAbsolutePath()));
|
||||||
usersFile = new File(localDBDir, "users.db");
|
usersFile = new File(localDbDir, "users.db");
|
||||||
idGeneratorFile = new File(localDBDir, "id_generator.db");
|
idGeneratorFile = new File(localDbDir, "id_generator.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +62,9 @@ public class PersistentLocalDb extends LocalDb {
|
|||||||
@Override
|
@Override
|
||||||
public void initializeUserStorage() {
|
public void initializeUserStorage() {
|
||||||
if (user == null) throw new NullPointerException("Client user is null");
|
if (user == null) throw new NullPointerException("Client user is null");
|
||||||
localDBFile = new File(localDBDir, user.getId() + ".db");
|
localDBFile = new File(localDBDir, user.getId() + ".db");
|
||||||
|
messageCacheFile = new File(localDBDir, user.getId() + "_message_cache.db");
|
||||||
|
statusCacheFile = new File(localDBDir, user.getId() + "_status_cache.db");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,8 +72,12 @@ public class PersistentLocalDb extends LocalDb {
|
|||||||
// Save users
|
// Save users
|
||||||
SerializationUtils.write(usersFile, users);
|
SerializationUtils.write(usersFile, users);
|
||||||
|
|
||||||
// Save chats
|
// Save user data
|
||||||
if (user != null) SerializationUtils.write(localDBFile, chats);
|
if (user != null) {
|
||||||
|
SerializationUtils.write(localDBFile, chats);
|
||||||
|
SerializationUtils.write(messageCacheFile, messageCache);
|
||||||
|
SerializationUtils.write(statusCacheFile, statusCache);
|
||||||
|
}
|
||||||
|
|
||||||
// Save id generator
|
// Save id generator
|
||||||
if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
|
if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
|
||||||
@ -82,7 +87,11 @@ public class PersistentLocalDb extends LocalDb {
|
|||||||
public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); }
|
public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); }
|
public void loadUserData() throws ClassNotFoundException, IOException {
|
||||||
|
chats = SerializationUtils.read(localDBFile, ArrayList.class);
|
||||||
|
messageCache = SerializationUtils.read(messageCacheFile, Cache.class);
|
||||||
|
statusCache = SerializationUtils.read(statusCacheFile, Cache.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadIdGenerator() {
|
public void loadIdGenerator() {
|
||||||
|
@ -9,7 +9,8 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.naming.TimeLimitExceededException;
|
import javax.naming.TimeLimitExceededException;
|
||||||
|
|
||||||
import envoy.client.Config;
|
import envoy.client.data.Cache;
|
||||||
|
import envoy.client.data.Config;
|
||||||
import envoy.client.data.LocalDb;
|
import envoy.client.data.LocalDb;
|
||||||
import envoy.client.event.SearchResultEvent;
|
import envoy.client.event.SearchResultEvent;
|
||||||
import envoy.client.util.EnvoyLog;
|
import envoy.client.util.EnvoyLog;
|
||||||
@ -51,16 +52,17 @@ public class Client implements Closeable {
|
|||||||
* will block for up to 5 seconds. If the handshake does exceed this time limit,
|
* will block for up to 5 seconds. If the handshake does exceed this time limit,
|
||||||
* an exception is thrown.
|
* an exception is thrown.
|
||||||
*
|
*
|
||||||
* @param credentials the login credentials of the user
|
* @param credentials the login credentials of the user
|
||||||
* @param localDb the local database used to persist the current
|
* @param localDb the local database used to persist the current
|
||||||
* {@link IdGenerator}
|
* {@link IdGenerator}
|
||||||
* @return a message cache containing all unread messages from the server that
|
* @param receivedMessageCache a message cache containing all unread messages
|
||||||
* can be relayed after initialization
|
* from the server that can be relayed after
|
||||||
|
* initialization
|
||||||
* @throws Exception if the online mode could not be entered or the request
|
* @throws Exception if the online mode could not be entered or the request
|
||||||
* failed for some other reason
|
* failed for some other reason
|
||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public MessageCache onlineInit(LoginCredentials credentials, LocalDb localDb) throws Exception {
|
public void onlineInit(LoginCredentials credentials, LocalDb localDb, Cache<Message> receivedMessageCache) throws Exception {
|
||||||
// Establish TCP connection
|
// Establish TCP connection
|
||||||
logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort()));
|
logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort()));
|
||||||
socket = new Socket(config.getServer(), config.getPort());
|
socket = new Socket(config.getServer(), config.getPort());
|
||||||
@ -69,13 +71,10 @@ public class Client implements Closeable {
|
|||||||
// Create message receiver
|
// Create message receiver
|
||||||
receiver = new Receiver(socket.getInputStream());
|
receiver = new Receiver(socket.getInputStream());
|
||||||
|
|
||||||
// Create cache for unread messages
|
|
||||||
final MessageCache cache = new MessageCache();
|
|
||||||
|
|
||||||
// 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 -> { logger.info("Acquired user object " + sender); this.sender = sender; });
|
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; });
|
receiver.registerProcessor(Contacts.class, contacts -> { logger.info("Acquired contacts object " + contacts); this.contacts = contacts; });
|
||||||
receiver.registerProcessor(Message.class, cache);
|
receiver.registerProcessor(Message.class, receivedMessageCache);
|
||||||
|
|
||||||
// Start receiver
|
// Start receiver
|
||||||
new Thread(receiver).start();
|
new Thread(receiver).start();
|
||||||
@ -98,15 +97,20 @@ public class Client implements Closeable {
|
|||||||
receiver.removeAllProcessors();
|
receiver.removeAllProcessors();
|
||||||
|
|
||||||
// Register processors for message and status handling
|
// Register processors for message and status handling
|
||||||
|
|
||||||
|
// Process incoming messages
|
||||||
final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor();
|
final ReceivedMessageProcessor receivedMessageProcessor = new ReceivedMessageProcessor();
|
||||||
receiver.registerProcessor(Message.class, receivedMessageProcessor);
|
receiver.registerProcessor(Message.class, receivedMessageProcessor);
|
||||||
|
|
||||||
// Relay cached unread messages
|
// Relay cached unread messages
|
||||||
cache.setProcessor(receivedMessageProcessor);
|
receivedMessageCache.setProcessor(receivedMessageProcessor);
|
||||||
|
|
||||||
// Process message status changes
|
// Process message status changes
|
||||||
receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor());
|
receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor());
|
||||||
|
|
||||||
|
// Process user status changes
|
||||||
|
receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(this));
|
||||||
|
|
||||||
// Process message ID generation
|
// Process message ID generation
|
||||||
receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator);
|
receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator);
|
||||||
|
|
||||||
@ -115,10 +119,19 @@ public class Client implements Closeable {
|
|||||||
|
|
||||||
// Request a generator if none is present or the existing one is consumed
|
// Request a generator if none is present or the existing one is consumed
|
||||||
if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator();
|
if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator();
|
||||||
|
|
||||||
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
|
* Sends a message to the server. The message's status will be incremented once
|
||||||
* it was delivered successfully.
|
* it was delivered successfully.
|
||||||
@ -197,4 +210,16 @@ public class Client implements Closeable {
|
|||||||
* @since Envoy v0.2-alpha
|
* @since Envoy v0.2-alpha
|
||||||
*/
|
*/
|
||||||
public boolean isOnline() { return online; }
|
public boolean isOnline() { return online; }
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* @return the contacts of this {@link Client}
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public Contacts getContacts() { return contacts; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param contacts the contacts to set
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public void setContacts(Contacts contacts) { this.contacts = contacts; }
|
||||||
|
}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
package envoy.client.net;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import envoy.client.util.EnvoyLog;
|
|
||||||
import envoy.data.Message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores messages in a queue until the application initialization is complete.
|
|
||||||
* The messages can then be relayed to a processor.<br>
|
|
||||||
* <br>
|
|
||||||
* Project: <strong>envoy-client</strong><br>
|
|
||||||
* File: <strong>MessageCache.java</strong><br>
|
|
||||||
* Created: <strong>4 Feb 2020</strong><br>
|
|
||||||
*
|
|
||||||
* @author Kai S. K. Engelbart
|
|
||||||
* @since Envoy v0.3-alpha
|
|
||||||
*/
|
|
||||||
public class MessageCache implements Consumer<Message> {
|
|
||||||
|
|
||||||
private final Queue<Message> messages = new LinkedList<>();
|
|
||||||
private Consumer<Message> processor;
|
|
||||||
|
|
||||||
private static final Logger logger = EnvoyLog.getLogger(MessageCache.class.getSimpleName());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a message to the cache.
|
|
||||||
*
|
|
||||||
* @since Envoy v0.3-alpha
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void accept(Message message) {
|
|
||||||
logger.info(String.format("Adding message %s to cache", message));
|
|
||||||
messages.add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the processor to which messages are relayed.
|
|
||||||
*
|
|
||||||
* @param processor the processor to set
|
|
||||||
* @since Envoy v0.3-alpha
|
|
||||||
*/
|
|
||||||
public void setProcessor(Consumer<Message> processor) { this.processor = processor; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relays all cached messages to the processor.
|
|
||||||
*
|
|
||||||
* @since Envoy v0.3-alpha
|
|
||||||
*/
|
|
||||||
public void relayMessages() { messages.forEach(processor::accept); }
|
|
||||||
}
|
|
@ -0,0 +1,37 @@
|
|||||||
|
package envoy.client.net;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import envoy.client.util.EnvoyLog;
|
||||||
|
import envoy.event.EventBus;
|
||||||
|
import envoy.event.UserStatusChangeEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>UserStatusChangeProcessor.java</strong><br>
|
||||||
|
* Created: <strong>2 Feb 2020</strong><br>
|
||||||
|
*
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public class UserStatusChangeProcessor implements Consumer<UserStatusChangeEvent> {
|
||||||
|
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param client the {@link Client} who receives an
|
||||||
|
* {@link UserStatusChangeEvent}
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
|
*/
|
||||||
|
public UserStatusChangeProcessor(Client client) { this.client = client; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(UserStatusChangeEvent evt) {
|
||||||
|
logger.info("Received " + evt);
|
||||||
|
client.getContacts().getContacts().stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get());
|
||||||
|
EventBus.getInstance().dispatch(evt);
|
||||||
|
}
|
||||||
|
}
|
103
src/main/java/envoy/client/net/WriteProxy.java
Normal file
103
src/main/java/envoy/client/net/WriteProxy.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
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.<br>
|
||||||
|
* <br>
|
||||||
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
* File: <strong>WriteProxy.java</strong><br>
|
||||||
|
* Created: <strong>6 Feb 2020</strong><br>
|
||||||
|
*
|
||||||
|
* @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() {
|
||||||
|
logger.info("Sending cached messages and message status change events...");
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ import envoy.client.data.Chat;
|
|||||||
import envoy.client.data.LocalDb;
|
import envoy.client.data.LocalDb;
|
||||||
import envoy.client.event.*;
|
import envoy.client.event.*;
|
||||||
import envoy.client.net.Client;
|
import envoy.client.net.Client;
|
||||||
|
import envoy.client.net.WriteProxy;
|
||||||
import envoy.client.ui.list.ComponentList;
|
import envoy.client.ui.list.ComponentList;
|
||||||
import envoy.client.ui.list.ComponentListModel;
|
import envoy.client.ui.list.ComponentListModel;
|
||||||
import envoy.client.ui.settings.SettingsScreen;
|
import envoy.client.ui.settings.SettingsScreen;
|
||||||
@ -41,8 +42,9 @@ import envoy.event.ContactOperationEvent.Operation;
|
|||||||
public class ChatWindow extends JFrame {
|
public class ChatWindow extends JFrame {
|
||||||
|
|
||||||
// User specific objects
|
// User specific objects
|
||||||
private Client client;
|
private Client client;
|
||||||
private LocalDb localDb;
|
private WriteProxy writeProxy;
|
||||||
|
private LocalDb localDb;
|
||||||
|
|
||||||
// GUI components
|
// GUI components
|
||||||
private JPanel contentPane = new JPanel();
|
private JPanel contentPane = new JPanel();
|
||||||
@ -359,6 +361,9 @@ public class ChatWindow extends JFrame {
|
|||||||
// Listen to theme changes
|
// Listen to theme changes
|
||||||
EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get()));
|
EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get()));
|
||||||
|
|
||||||
|
// Listen to user status changes
|
||||||
|
EventBus.getInstance().register(UserStatusChangeEvent.class, (evt) -> { userList.revalidate(); userList.repaint(); });
|
||||||
|
|
||||||
// Listen to received messages
|
// Listen to received messages
|
||||||
EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> {
|
EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> {
|
||||||
Message message = ((MessageCreationEvent) evt).get();
|
Message message = ((MessageCreationEvent) evt).get();
|
||||||
@ -498,8 +503,7 @@ public class ChatWindow extends JFrame {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Send message
|
// Send message
|
||||||
// TODO: Store offline messages
|
writeProxy.writeMessage(message);
|
||||||
client.sendMessage(message);
|
|
||||||
|
|
||||||
// Add message to PersistentLocalDb and update UI
|
// Add message to PersistentLocalDb and update UI
|
||||||
currentChat.appendMessage(message);
|
currentChat.appendMessage(message);
|
||||||
@ -544,7 +548,7 @@ public class ChatWindow extends JFrame {
|
|||||||
|
|
||||||
private void readCurrentChat() {
|
private void readCurrentChat() {
|
||||||
try {
|
try {
|
||||||
currentChat.read(client);
|
currentChat.read(writeProxy);
|
||||||
messageList.synchronizeModel();
|
messageList.synchronizeModel();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -571,24 +575,23 @@ public class ChatWindow extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link Client} used by this {@link ChatWindow}.
|
* Initializes the components responsible server communication and
|
||||||
|
* persistence.<br>
|
||||||
|
* <br>
|
||||||
|
* This will trigger the display of the contact list.
|
||||||
*
|
*
|
||||||
* @param client the {@link Client} used to send and receive messages
|
* @param client the client used to send and receive messages
|
||||||
* @since Envoy v0.2-alpha
|
* @param localDb the local database used to manage stored messages
|
||||||
|
* and users
|
||||||
|
* @param writeProxy the write proxy used to send messages and status change
|
||||||
|
* events to the server or cache them inside the local
|
||||||
|
* database
|
||||||
|
* @since Envoy v0.3-alpha
|
||||||
*/
|
*/
|
||||||
public void setClient(Client client) { this.client = client; }
|
public void initContent(Client client, LocalDb localDb, WriteProxy writeProxy) {
|
||||||
|
this.client = client;
|
||||||
/**
|
this.localDb = localDb;
|
||||||
* Sets the {@link LocalDb} used by this {@link ChatWindow}. After
|
this.writeProxy = writeProxy;
|
||||||
* invoking this
|
|
||||||
* method, users and chats will be loaded from the database into the GUI.
|
|
||||||
*
|
|
||||||
* @param localDb the {@link LocalDb} used to manage stored messages
|
|
||||||
* and users
|
|
||||||
* @since Envoy v0.2-alpha
|
|
||||||
*/
|
|
||||||
public void setLocalDB(LocalDb localDb) {
|
|
||||||
this.localDb = localDb;
|
|
||||||
loadUsersAndChats();
|
loadUsersAndChats();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,13 @@ import javax.swing.JFrame;
|
|||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import envoy.client.Config;
|
|
||||||
import envoy.client.Settings;
|
import envoy.client.Settings;
|
||||||
import envoy.client.data.LocalDb;
|
import envoy.client.data.*;
|
||||||
import envoy.client.data.PersistentLocalDb;
|
|
||||||
import envoy.client.data.TransientLocalDb;
|
|
||||||
import envoy.client.net.Client;
|
import envoy.client.net.Client;
|
||||||
import envoy.client.net.MessageCache;
|
import envoy.client.net.WriteProxy;
|
||||||
import envoy.client.util.EnvoyLog;
|
import envoy.client.util.EnvoyLog;
|
||||||
import envoy.data.LoginCredentials;
|
import envoy.data.LoginCredentials;
|
||||||
|
import envoy.data.Message;
|
||||||
import envoy.data.User;
|
import envoy.data.User;
|
||||||
import envoy.exception.EnvoyException;
|
import envoy.exception.EnvoyException;
|
||||||
|
|
||||||
@ -64,7 +62,7 @@ public class Startup {
|
|||||||
// Override configuration values with command line arguments
|
// Override configuration values with command line arguments
|
||||||
if (args.length > 0) config.load(args);
|
if (args.length > 0) config.load(args);
|
||||||
|
|
||||||
// Check if all configuration values have been initialized
|
// Check if all mandatory configuration values have been initialized
|
||||||
if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined");
|
if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
JOptionPane
|
JOptionPane
|
||||||
@ -77,8 +75,8 @@ public class Startup {
|
|||||||
EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier());
|
EnvoyLog.setFileLevelBarrier(config.getFileLevelBarrier());
|
||||||
EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier());
|
EnvoyLog.setConsoleLevelBarrier(config.getConsoleLevelBarrier());
|
||||||
|
|
||||||
// Ask the user for their user name and password
|
// Acquire login credentials
|
||||||
LoginCredentials credentials = new LoginDialog().getCredentials();
|
LoginCredentials credentials = config.hasLoginCredentials() ? config.getLoginCredentials() : new LoginDialog().getCredentials();
|
||||||
|
|
||||||
if (credentials == null) {
|
if (credentials == null) {
|
||||||
logger.info("The login process has been aborted by the user. Exiting...");
|
logger.info("The login process has been aborted by the user. Exiting...");
|
||||||
@ -108,11 +106,11 @@ public class Startup {
|
|||||||
// Acquire the client user (with ID) either from the server or from the local
|
// Acquire the client user (with ID) either from the server or from the local
|
||||||
// database, which triggers offline mode
|
// database, which triggers offline mode
|
||||||
Client client = new Client();
|
Client client = new Client();
|
||||||
MessageCache cache = null;
|
Cache<Message> cache = new Cache<>();
|
||||||
try {
|
try {
|
||||||
// Try entering online mode first
|
// Try entering online mode first
|
||||||
localDb.loadIdGenerator();
|
localDb.loadIdGenerator();
|
||||||
cache = client.onlineInit(credentials, localDb);
|
client.onlineInit(credentials, localDb, cache);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
logger.warning("Could not connect to server. Trying offline mode...");
|
logger.warning("Could not connect to server. Trying offline mode...");
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
@ -139,7 +137,7 @@ public class Startup {
|
|||||||
// Initialize chats in local database
|
// Initialize chats in local database
|
||||||
try {
|
try {
|
||||||
localDb.initializeUserStorage();
|
localDb.initializeUserStorage();
|
||||||
localDb.loadChats();
|
localDb.loadUserData();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
// The local database file has not yet been created, probably first login
|
// The local database file has not yet been created, probably first login
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -150,14 +148,22 @@ public class Startup {
|
|||||||
JOptionPane.WARNING_MESSAGE);
|
JOptionPane.WARNING_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save all users to the local database
|
// Initialize write proxy
|
||||||
if (client.isOnline()) localDb.setUsers(client.getUsers());
|
final WriteProxy writeProxy = client.createWriteProxy(localDb);
|
||||||
|
|
||||||
|
// Save all users to the local database and flush cache
|
||||||
|
if (client.isOnline()) {
|
||||||
|
localDb.setUsers(client.getUsers());
|
||||||
|
writeProxy.flushCache();
|
||||||
|
}
|
||||||
|
|
||||||
// Display ChatWindow and StatusTrayIcon
|
// Display ChatWindow and StatusTrayIcon
|
||||||
EventQueue.invokeLater(() -> {
|
EventQueue.invokeLater(() -> {
|
||||||
try {
|
try {
|
||||||
chatWindow.setClient(client);
|
chatWindow.initContent(client, localDb, writeProxy);
|
||||||
chatWindow.setLocalDB(localDb);
|
|
||||||
|
// Relay unread messages from cache
|
||||||
|
if (cache != null) cache.relay();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new StatusTrayIcon(chatWindow).show();
|
new StatusTrayIcon(chatWindow).show();
|
||||||
@ -177,9 +183,6 @@ public class Startup {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Relay unread messages from cache
|
|
||||||
if (cache != null) cache.relayMessages();
|
|
||||||
|
|
||||||
// Save Settings and PersistentLocalDb on shutdown
|
// Save Settings and PersistentLocalDb on shutdown
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -4,7 +4,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
import envoy.client.Config;
|
import envoy.client.data.Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>envoy-client</strong><br>
|
* Project: <strong>envoy-client</strong><br>
|
||||||
|
Reference in New Issue
Block a user