Remove TransientLocalDB and no-db Config Value #24
@@ -35,7 +35,6 @@ public final class ClientConfig extends Config {
 | 
				
			|||||||
		put("server", "s", identity());
 | 
							put("server", "s", identity());
 | 
				
			||||||
		put("port", "p", Integer::parseInt);
 | 
							put("port", "p", Integer::parseInt);
 | 
				
			||||||
		put("localDB", "db", File::new);
 | 
							put("localDB", "db", File::new);
 | 
				
			||||||
		put("ignoreLocalDB", "nodb", Boolean::parseBoolean);
 | 
					 | 
				
			||||||
		put("user", "u", identity());
 | 
							put("user", "u", identity());
 | 
				
			||||||
		put("password", "pw", identity());
 | 
							put("password", "pw", identity());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -58,12 +57,6 @@ public final class ClientConfig extends Config {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public File getLocalDB() { return (File) items.get("localDB").get(); }
 | 
						public File getLocalDB() { return (File) items.get("localDB").get(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return {@code true} if the local database is to be ignored
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public Boolean isIgnoreLocalDB() { return (Boolean) items.get("ignoreLocalDB").get(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the user name
 | 
						 * @return the user name
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,19 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.*;
 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.event.GroupResize;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.event.MessageStatusChange;
 | 
					import envoy.util.SerializationUtils;
 | 
				
			||||||
import envoy.event.NameChange;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Stores information about the current {@link User} and their {@link Chat}s.
 | 
					 * Stores information about the current {@link User} and their {@link Chat}s.
 | 
				
			||||||
 * For message ID generation a {@link IDGenerator} is stored as well.
 | 
					 * For message ID generation a {@link IDGenerator} is stored as well.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * The managed objects are stored inside a folder in the local file system.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Project: <strong>envoy-client</strong><br>
 | 
				
			||||||
 * File: <strong>LocalDB.java</strong><br>
 | 
					 * File: <strong>LocalDB.java</strong><br>
 | 
				
			||||||
 * Created: <strong>3 Feb 2020</strong><br>
 | 
					 * Created: <strong>3 Feb 2020</strong><br>
 | 
				
			||||||
@@ -19,60 +21,105 @@ import envoy.event.NameChange;
 | 
				
			|||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class LocalDB {
 | 
					public final class LocalDB {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected User				user;
 | 
						private User				user;
 | 
				
			||||||
	protected Map<String, User>	users		= new HashMap<>();
 | 
						private Map<String, User>	users		= new HashMap<>();
 | 
				
			||||||
	protected List<Chat>		chats		= new ArrayList<>();
 | 
						private List<Chat>			chats		= new ArrayList<>();
 | 
				
			||||||
	protected IDGenerator		idGenerator;
 | 
						private IDGenerator			idGenerator;
 | 
				
			||||||
	protected CacheMap			cacheMap	= new CacheMap();
 | 
						private CacheMap			cacheMap	= new CacheMap();
 | 
				
			||||||
	protected Instant			lastSync	= Instant.EPOCH;
 | 
						private Instant				lastSync	= Instant.EPOCH;
 | 
				
			||||||
 | 
						private File				dbDir, userFile, idGeneratorFile, usersFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						/**
 | 
				
			||||||
 | 
						 * Constructs an empty local database. To serialize any user-specific data to
 | 
				
			||||||
 | 
						 * the file system, call {@link LocalDB#initializeUserStorage()} first
 | 
				
			||||||
 | 
						 * and then {@link LocalDB#save(boolean)}.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param dbDir the directory in which to persist data
 | 
				
			||||||
 | 
						 * @throws IOException if {@code dbDir} is a file (and not a directory)
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public LocalDB(File dbDir) throws IOException {
 | 
				
			||||||
 | 
							this.dbDir = dbDir;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Test if the database directory is actually a directory
 | 
				
			||||||
 | 
							if (dbDir.exists() && !dbDir.isDirectory())
 | 
				
			||||||
 | 
								throw new IOException(String.format("LocalDBDir '%s' is not a directory!", dbDir.getAbsolutePath()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize global files
 | 
				
			||||||
 | 
							idGeneratorFile	= new File(dbDir, "id_gen.db");
 | 
				
			||||||
 | 
							usersFile		= new File(dbDir, "users.db");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize offline caches
 | 
				
			||||||
		cacheMap.put(Message.class, new Cache<>());
 | 
							cacheMap.put(Message.class, new Cache<>());
 | 
				
			||||||
		cacheMap.put(MessageStatusChange.class, new Cache<>());
 | 
							cacheMap.put(MessageStatusChange.class, new Cache<>());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Initializes a storage space for a user-specific list of chats.
 | 
						 * Creates a database file for a user-specific list of chats.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @throws IllegalStateException if the client user is not specified
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void initializeUserStorage() {}
 | 
						public void initializeUserStorage() {
 | 
				
			||||||
 | 
							if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
 | 
				
			||||||
 | 
							userFile = new File(dbDir, user.getID() + ".db");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Stores all users. If the client user is specified, their chats will be stored
 | 
						 * Stores all users. If the client user is specified, their chats will be stored
 | 
				
			||||||
	 * as well. The message id generator will also be saved if present.
 | 
						 * as well. The message id generator will also be saved if present.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param isOnline determines which {@code lastSync} time stamp is saved
 | 
						 * @param isOnline determines which {@code lastSync} time stamp is saved
 | 
				
			||||||
	 * @throws Exception if the saving process failed
 | 
						 * @throws IOException if the saving process failed
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void save(boolean isOnline) throws Exception {}
 | 
						public void save(boolean isOnline) throws IOException {
 | 
				
			||||||
 | 
							// Save users
 | 
				
			||||||
 | 
							SerializationUtils.write(usersFile, users);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Save user data and last sync time stamp
 | 
				
			||||||
 | 
							if (user != null) SerializationUtils.write(userFile, chats, cacheMap, isOnline ? Instant.now() : lastSync);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Save id generator
 | 
				
			||||||
 | 
							if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Loads all user data.
 | 
						 * Loads all user data.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @throws Exception if the loading process failed
 | 
						 * @throws ClassNotFoundException if the loading process failed
 | 
				
			||||||
 | 
						 * @throws IOException            if the loading process failed
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void loadUsers() throws Exception {}
 | 
						public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Loads all data of the client user.
 | 
						 * Loads all data of the client user.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @throws Exception if the loading process failed
 | 
						 * @throws ClassNotFoundException if the loading process failed
 | 
				
			||||||
 | 
						 * @throws IOException            if the loading process failed
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void loadUserData() throws Exception {}
 | 
						public void loadUserData() throws ClassNotFoundException, IOException {
 | 
				
			||||||
 | 
							try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
				
			||||||
 | 
								chats		= (ArrayList<Chat>) in.readObject();
 | 
				
			||||||
 | 
								cacheMap	= (CacheMap) in.readObject();
 | 
				
			||||||
 | 
								lastSync	= (Instant) in.readObject();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Loads the ID generator. Any exception thrown during this process is ignored.
 | 
						 * Loads the ID generator. Any exception thrown during this process is ignored.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void loadIDGenerator() {}
 | 
						public void loadIDGenerator() {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								idGenerator = SerializationUtils.read(idGeneratorFile, IDGenerator.class);
 | 
				
			||||||
 | 
							} catch (ClassNotFoundException | IOException e) {}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Synchronizes the contact list of the client user with the chat and user
 | 
						 * Synchronizes the contact list of the client user with the chat and user
 | 
				
			||||||
	 * storage.
 | 
						 * storage.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,90 +0,0 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.*;
 | 
					 | 
				
			||||||
import java.time.Instant;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.HashMap;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import envoy.data.IDGenerator;
 | 
					 | 
				
			||||||
import envoy.util.SerializationUtils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Implements a {@link LocalDB} in a way that stores all information inside a
 | 
					 | 
				
			||||||
 * folder on the local file system.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>PersistentLocalDB.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>27.10.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.1-alpha
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class PersistentLocalDB extends LocalDB {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private File dbDir, userFile, idGeneratorFile, usersFile;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Constructs an empty local database. To serialize any user-specific data to
 | 
					 | 
				
			||||||
	 * the file system, call {@link PersistentLocalDB#initializeUserStorage()} first
 | 
					 | 
				
			||||||
	 * and then {@link PersistentLocalDB#save(boolean)}.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param dbDir the directory in which to persist data
 | 
					 | 
				
			||||||
	 * @throws IOException if {@code dbDir} is a file (and not a directory)
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-alpha
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public PersistentLocalDB(File dbDir) throws IOException {
 | 
					 | 
				
			||||||
		this.dbDir = dbDir;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Test if the database directory is actually a directory
 | 
					 | 
				
			||||||
		if (dbDir.exists() && !dbDir.isDirectory())
 | 
					 | 
				
			||||||
			throw new IOException(String.format("LocalDBDir '%s' is not a directory!", dbDir.getAbsolutePath()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Initialize global files
 | 
					 | 
				
			||||||
		idGeneratorFile	= new File(dbDir, "id_gen.db");
 | 
					 | 
				
			||||||
		usersFile		= new File(dbDir, "users.db");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Creates a database file for a user-specific list of chats.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @throws IllegalStateException if the client user is not specified
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-alpha
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void initializeUserStorage() {
 | 
					 | 
				
			||||||
		if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
 | 
					 | 
				
			||||||
		userFile = new File(dbDir, user.getID() + ".db");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void save(boolean isOnline) throws IOException {
 | 
					 | 
				
			||||||
		// Save users
 | 
					 | 
				
			||||||
		SerializationUtils.write(usersFile, users);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Save user data and last sync time stamp
 | 
					 | 
				
			||||||
		if (user != null) SerializationUtils.write(userFile, chats, cacheMap, isOnline ? Instant.now() : lastSync);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Save id generator
 | 
					 | 
				
			||||||
		if (hasIDGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void loadUserData() throws ClassNotFoundException, IOException {
 | 
					 | 
				
			||||||
		try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
					 | 
				
			||||||
			chats		= (ArrayList<Chat>) in.readObject();
 | 
					 | 
				
			||||||
			cacheMap	= (CacheMap) in.readObject();
 | 
					 | 
				
			||||||
			lastSync	= (Instant) in.readObject();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void loadIDGenerator() {
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			idGenerator = SerializationUtils.read(idGeneratorFile, IDGenerator.class);
 | 
					 | 
				
			||||||
		} catch (ClassNotFoundException | IOException e) {}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Implements a {@link LocalDB} in a way that does not persist any information
 | 
					 | 
				
			||||||
 * after application shutdown.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>TransientLocalDB.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>3 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class TransientLocalDB extends LocalDB {
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,12 +1,9 @@
 | 
				
			|||||||
package envoy.client.ui;
 | 
					package envoy.client.ui;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.*;
 | 
				
			||||||
import java.io.FileNotFoundException;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
import java.util.concurrent.TimeoutException;
 | 
					import java.util.concurrent.TimeoutException;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.application.Application;
 | 
					import javafx.application.Application;
 | 
				
			||||||
import javafx.scene.control.Alert;
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
@@ -19,8 +16,7 @@ import envoy.client.ui.SceneContext.SceneInfo;
 | 
				
			|||||||
import envoy.client.ui.controller.LoginScene;
 | 
					import envoy.client.ui.controller.LoginScene;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.User.UserStatus;
 | 
					import envoy.data.User.UserStatus;
 | 
				
			||||||
import envoy.event.GroupMessageStatusChange;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.event.MessageStatusChange;
 | 
					 | 
				
			||||||
import envoy.exception.EnvoyException;
 | 
					import envoy.exception.EnvoyException;
 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,11 +66,8 @@ public final class Startup extends Application {
 | 
				
			|||||||
		logger.log(Level.INFO, "Envoy starting...");
 | 
							logger.log(Level.INFO, "Envoy starting...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Initialize the local database
 | 
							// Initialize the local database
 | 
				
			||||||
		if (config.isIgnoreLocalDB()) {
 | 
							try {
 | 
				
			||||||
			localDB = new TransientLocalDB();
 | 
								localDB = new LocalDB(new File(config.getHomeDirectory(), config.getLocalDB().getPath()));
 | 
				
			||||||
			new Alert(AlertType.WARNING, "Ignoring local database.\nMessages will not be saved!").showAndWait();
 | 
					 | 
				
			||||||
		} else try {
 | 
					 | 
				
			||||||
			localDB = new PersistentLocalDB(new File(config.getHomeDirectory(), config.getLocalDB().getPath()));
 | 
					 | 
				
			||||||
		} catch (final IOException e3) {
 | 
							} catch (final IOException e3) {
 | 
				
			||||||
			logger.log(Level.SEVERE, "Could not initialize local database: ", e3);
 | 
								logger.log(Level.SEVERE, "Could not initialize local database: ", e3);
 | 
				
			||||||
			new Alert(AlertType.ERROR, "Could not initialize local database!\n" + e3).showAndWait();
 | 
								new Alert(AlertType.ERROR, "Could not initialize local database!\n" + e3).showAndWait();
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user