Prepare handshake synchronization
Common * Replace LocalDateTime with Instant everywhere Client * Display message creation date with system time zone in MessageControl * LocalDB#users now strictly contains Users * lastSync time stamp in LocalDB (saved per user) * isOnline parameter in save function (lastSync updated if true) * lastSync time stamp in LoginCredentials * No ClientConfig#getLoginCredentials because of missing information, moved to LoginScene * Pass LocalDB#lastSync to LoginCredentials in LoginScene Server * Explicit lastSync parameter for PersistenceManager#getPending(Group)Messages This sends the correct time stamp to the server, however the JPQL queries have yet to be adjusted.
This commit is contained in:
		@@ -5,10 +5,8 @@ import static java.util.function.Function.identity;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
 | 
			
		||||
import envoy.client.ui.Startup;
 | 
			
		||||
import envoy.data.Config;
 | 
			
		||||
import envoy.data.ConfigItem;
 | 
			
		||||
import envoy.data.LoginCredentials;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements a configuration specific to the Envoy Client with default values
 | 
			
		||||
@@ -105,11 +103,4 @@ public class ClientConfig extends Config {
 | 
			
		||||
	 * @since Envoy Client 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 Client v0.3-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public LoginCredentials getLoginCredentials() { return new LoginCredentials(getUser(), getPassword(), false, Startup.VERSION); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
package envoy.client.data;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
import envoy.client.net.WriteProxy;
 | 
			
		||||
import envoy.data.Contact;
 | 
			
		||||
@@ -46,7 +46,7 @@ public class GroupChat extends Chat {
 | 
			
		||||
				else {
 | 
			
		||||
					gmsg.getMemberStatuses().replace(sender.getID(), MessageStatus.READ);
 | 
			
		||||
					writeProxy
 | 
			
		||||
						.writeMessageStatusChange(new GroupMessageStatusChange(gmsg.getID(), MessageStatus.READ, LocalDateTime.now(), sender.getID()));
 | 
			
		||||
						.writeMessageStatusChange(new GroupMessageStatusChange(gmsg.getID(), MessageStatus.READ, Instant.now(), sender.getID()));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package envoy.client.data;
 | 
			
		||||
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
@@ -20,11 +21,12 @@ import envoy.event.NameChange;
 | 
			
		||||
 */
 | 
			
		||||
public abstract class LocalDB {
 | 
			
		||||
 | 
			
		||||
	protected User					user;
 | 
			
		||||
	protected Map<String, Contact>	users		= new HashMap<>();
 | 
			
		||||
	protected List<Chat>			chats		= new ArrayList<>();
 | 
			
		||||
	protected IDGenerator			idGenerator;
 | 
			
		||||
	protected CacheMap				cacheMap	= new CacheMap();
 | 
			
		||||
	protected User				user;
 | 
			
		||||
	protected Map<String, User>	users		= new HashMap<>();
 | 
			
		||||
	protected List<Chat>		chats		= new ArrayList<>();
 | 
			
		||||
	protected IDGenerator		idGenerator;
 | 
			
		||||
	protected CacheMap			cacheMap	= new CacheMap();
 | 
			
		||||
	protected Instant			lastSync	= Instant.EPOCH;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		cacheMap.put(Message.class, new Cache<>());
 | 
			
		||||
@@ -42,10 +44,11 @@ public abstract class LocalDB {
 | 
			
		||||
	 * 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.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param isOnline determines which {@code lastSync} time stamp is saved
 | 
			
		||||
	 * @throws Exception if the saving process failed
 | 
			
		||||
	 * @since Envoy Client v0.3-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void save() throws Exception {}
 | 
			
		||||
	public void save(boolean isOnline) throws Exception {}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Loads all user data.
 | 
			
		||||
@@ -77,7 +80,7 @@ public abstract class LocalDB {
 | 
			
		||||
	 * @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));
 | 
			
		||||
		user.getContacts().stream().filter(u -> u instanceof User && !users.containsKey(u.getName())).forEach(u -> users.put(u.getName(), (User) u));
 | 
			
		||||
		users.put(user.getName(), user);
 | 
			
		||||
 | 
			
		||||
		// Synchronize user status data
 | 
			
		||||
@@ -98,7 +101,7 @@ public abstract class LocalDB {
 | 
			
		||||
	 *         user names as keys
 | 
			
		||||
	 * @since Envoy Client v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public Map<String, Contact> getUsers() { return users; }
 | 
			
		||||
	public Map<String, User> getUsers() { return users; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return all saved {@link Chat} objects that list the client user as the
 | 
			
		||||
@@ -148,6 +151,12 @@ public abstract class LocalDB {
 | 
			
		||||
	 */
 | 
			
		||||
	public CacheMap getCacheMap() { return cacheMap; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the time stamp when the database was last saved
 | 
			
		||||
	 * @since Envoy Client v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public Instant getLastSync() { return lastSync; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Searches for a message by ID.
 | 
			
		||||
	 *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package envoy.client.data;
 | 
			
		||||
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +27,7 @@ public final class PersistentLocalDB extends LocalDB {
 | 
			
		||||
	/**
 | 
			
		||||
	 * 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()}.
 | 
			
		||||
	 * 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)
 | 
			
		||||
@@ -57,12 +58,12 @@ public final class PersistentLocalDB extends LocalDB {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void save() throws IOException {
 | 
			
		||||
	public void save(boolean isOnline) throws IOException {
 | 
			
		||||
		// Save users
 | 
			
		||||
		SerializationUtils.write(usersFile, users);
 | 
			
		||||
 | 
			
		||||
		// Save user data
 | 
			
		||||
		if (user != null) SerializationUtils.write(userFile, chats, cacheMap);
 | 
			
		||||
		// 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);
 | 
			
		||||
@@ -76,6 +77,7 @@ public final class PersistentLocalDB extends LocalDB {
 | 
			
		||||
		try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
			
		||||
			chats		= (ArrayList<Chat>) in.readObject();
 | 
			
		||||
			cacheMap	= (CacheMap) in.readObject();
 | 
			
		||||
			lastSync	= (Instant) in.readObject();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -121,12 +121,13 @@ public final class Startup extends Application {
 | 
			
		||||
	@Override
 | 
			
		||||
	public void stop() {
 | 
			
		||||
		try {
 | 
			
		||||
			logger.log(Level.INFO, "Saving local database and settings...");
 | 
			
		||||
			localDB.save(client.isOnline());
 | 
			
		||||
			Settings.getInstance().save();
 | 
			
		||||
 | 
			
		||||
			logger.log(Level.INFO, "Closing connection...");
 | 
			
		||||
			client.close();
 | 
			
		||||
 | 
			
		||||
			logger.log(Level.INFO, "Saving local database and settings...");
 | 
			
		||||
			localDB.save();
 | 
			
		||||
			Settings.getInstance().save();
 | 
			
		||||
			logger.log(Level.INFO, "Envoy was terminated by its user");
 | 
			
		||||
		} catch (final Exception e) {
 | 
			
		||||
			logger.log(Level.SEVERE, "Unable to save local files: ", e);
 | 
			
		||||
 
 | 
			
		||||
@@ -183,12 +183,11 @@ public final class ChatScene implements Restorable {
 | 
			
		||||
			final var contact = e.get();
 | 
			
		||||
			switch (e.getOperationType()) {
 | 
			
		||||
				case ADD:
 | 
			
		||||
					localDB.getUsers().put(contact.getName(), contact);
 | 
			
		||||
					if (contact instanceof User) localDB.getUsers().put(contact.getName(), (User) contact);
 | 
			
		||||
					Chat chat = contact instanceof User ? new Chat(contact) : new GroupChat(client.getSender(), contact);
 | 
			
		||||
					Platform.runLater(() -> chatList.getItems().add(chat));
 | 
			
		||||
					break;
 | 
			
		||||
				case REMOVE:
 | 
			
		||||
					localDB.getUsers().remove(contact.getName());
 | 
			
		||||
					Platform.runLater(() -> chatList.getItems().removeIf(c -> c.getRecipient().equals(contact)));
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package envoy.client.ui.controller;
 | 
			
		||||
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.concurrent.TimeoutException;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
@@ -94,7 +95,8 @@ public final class LoginScene {
 | 
			
		||||
		userTextField.requestFocus();
 | 
			
		||||
 | 
			
		||||
		// Perform automatic login if configured
 | 
			
		||||
		if (config.hasLoginCredentials()) performHandshake(config.getLoginCredentials());
 | 
			
		||||
		if (config.hasLoginCredentials())
 | 
			
		||||
			performHandshake(new LoginCredentials(config.getUser(), config.getPassword(), false, Startup.VERSION, loadLastSync(config.getUser())));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
@@ -108,12 +110,13 @@ public final class LoginScene {
 | 
			
		||||
			new Alert(AlertType.ERROR, "The entered user name is not valid (" + Bounds.CONTACT_NAME_PATTERN + ")").showAndWait();
 | 
			
		||||
			userTextField.getTextField().clear();
 | 
			
		||||
		} else performHandshake(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), registerCheckBox.isSelected(),
 | 
			
		||||
				Startup.VERSION));
 | 
			
		||||
				Startup.VERSION, loadLastSync(userTextField.getTextField().getText())));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
	private void offlineModeButtonPressed() {
 | 
			
		||||
		attemptOfflineMode(new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), false, Startup.VERSION));
 | 
			
		||||
		attemptOfflineMode(
 | 
			
		||||
				new LoginCredentials(userTextField.getTextField().getText(), passwordField.getText(), false, Startup.VERSION, localDB.getLastSync()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@FXML
 | 
			
		||||
@@ -130,6 +133,18 @@ public final class LoginScene {
 | 
			
		||||
		System.exit(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Instant loadLastSync(String identifier) {
 | 
			
		||||
		try {
 | 
			
		||||
			localDB.loadUsers();
 | 
			
		||||
			localDB.setUser(localDB.getUsers().get(identifier));
 | 
			
		||||
			localDB.initializeUserStorage();
 | 
			
		||||
			localDB.loadUserData();
 | 
			
		||||
		} catch (Exception e) {
 | 
			
		||||
			// User storage empty, wrong user name etc. -> default lastSync
 | 
			
		||||
		}
 | 
			
		||||
		return localDB.getLastSync();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void performHandshake(LoginCredentials credentials) {
 | 
			
		||||
		try {
 | 
			
		||||
			client.performHandshake(credentials, cacheMap);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package envoy.client.ui.listcell;
 | 
			
		||||
import java.awt.Toolkit;
 | 
			
		||||
import java.awt.datatransfer.StringSelection;
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.time.ZoneId;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
@@ -35,11 +36,12 @@ import envoy.util.EnvoyLog;
 | 
			
		||||
 */
 | 
			
		||||
public class MessageControl extends Label {
 | 
			
		||||
 | 
			
		||||
	private static User								client;
 | 
			
		||||
	private static final DateTimeFormatter			dateFormat		= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
 | 
			
		||||
	private static final Map<MessageStatus, Image>	statusImages	= IconUtil.loadByEnum(MessageStatus.class, 16);
 | 
			
		||||
	private static User client;
 | 
			
		||||
 | 
			
		||||
	private static final Logger logger = EnvoyLog.getLogger(MessageControl.class);
 | 
			
		||||
	private static final DateTimeFormatter			dateFormat		= DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
 | 
			
		||||
		.withZone(ZoneId.systemDefault());
 | 
			
		||||
	private static final Map<MessageStatus, Image>	statusImages	= IconUtil.loadByEnum(MessageStatus.class, 16);
 | 
			
		||||
	private static final Logger						logger			= EnvoyLog.getLogger(MessageControl.class);
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 *
 | 
			
		||||
@@ -68,7 +70,8 @@ public class MessageControl extends Label {
 | 
			
		||||
		if (message.hasAttachment()) {
 | 
			
		||||
			switch (message.getAttachment().getType()) {
 | 
			
		||||
				case PICTURE:
 | 
			
		||||
					vbox.getChildren().add(new ImageView(new Image(new ByteArrayInputStream(message.getAttachment().getData()), 256, 256, true, true)));
 | 
			
		||||
					vbox.getChildren()
 | 
			
		||||
						.add(new ImageView(new Image(new ByteArrayInputStream(message.getAttachment().getData()), 256, 256, true, true)));
 | 
			
		||||
					break;
 | 
			
		||||
				case VIDEO:
 | 
			
		||||
					break;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@@ -16,7 +16,7 @@ public final class GroupMessage extends Message {
 | 
			
		||||
 | 
			
		||||
	private final Map<Long, MessageStatus> memberStatuses;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 0L;
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes a {@link GroupMessage} with values for all of its properties. The
 | 
			
		||||
@@ -38,9 +38,9 @@ public final class GroupMessage extends Message {
 | 
			
		||||
	 * @param forwarded      whether this message was forwarded
 | 
			
		||||
	 * @param memberStatuses a map of all members and their status according to this
 | 
			
		||||
	 *                       {@link GroupMessage}
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	GroupMessage(long id, long senderID, long groupID, LocalDateTime creationDate, LocalDateTime receivedDate, LocalDateTime readDate, String text,
 | 
			
		||||
	GroupMessage(long id, long senderID, long groupID, Instant creationDate, Instant receivedDate, Instant readDate, String text,
 | 
			
		||||
			Attachment attachment, MessageStatus status, boolean forwarded, Map<Long, MessageStatus> memberStatuses) {
 | 
			
		||||
		super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status, forwarded);
 | 
			
		||||
		this.memberStatuses = memberStatuses;
 | 
			
		||||
@@ -55,10 +55,10 @@ public final class GroupMessage extends Message {
 | 
			
		||||
		setStatus(Collections.min(memberStatuses.values()));
 | 
			
		||||
		switch (getStatus()) {
 | 
			
		||||
			case RECEIVED:
 | 
			
		||||
				setReceivedDate(LocalDateTime.now());
 | 
			
		||||
				setReceivedDate(Instant.now());
 | 
			
		||||
				break;
 | 
			
		||||
			case READ:
 | 
			
		||||
				setReadDate(LocalDateTime.now());
 | 
			
		||||
				setReadDate(Instant.now());
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package envoy.data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains a {@link User}'s login / registration information as well as the
 | 
			
		||||
@@ -17,8 +18,9 @@ public final class LoginCredentials implements Serializable {
 | 
			
		||||
 | 
			
		||||
	private final String	identifier, password, clientVersion;
 | 
			
		||||
	private final boolean	registration;
 | 
			
		||||
	private final Instant	lastSync;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 2;
 | 
			
		||||
	private static final long serialVersionUID = 3;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes login credentials for a handshake.
 | 
			
		||||
@@ -28,18 +30,24 @@ public final class LoginCredentials implements Serializable {
 | 
			
		||||
	 * @param registration  signifies that these credentials are used for user
 | 
			
		||||
	 *                      registration instead of user login
 | 
			
		||||
	 * @param clientVersion the version of the client sending these credentials
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 * @param lastSync      the time stamp of the last synchronization
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LoginCredentials(String identifier, String password, boolean registration, String clientVersion) {
 | 
			
		||||
	public LoginCredentials(String identifier, String password, boolean registration, String clientVersion, Instant lastSync) {
 | 
			
		||||
		this.identifier		= identifier;
 | 
			
		||||
		this.password		= password;
 | 
			
		||||
		this.registration	= registration;
 | 
			
		||||
		this.clientVersion	= clientVersion;
 | 
			
		||||
		this.lastSync		= lastSync;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() {
 | 
			
		||||
		return String.format("LoginCredentials[identifier=%s,registration=%b,clientVersion=%s]", identifier, registration, clientVersion);
 | 
			
		||||
		return String.format("LoginCredentials[identifier=%s,registration=%b,clientVersion=%s,lastSync=%s]",
 | 
			
		||||
				identifier,
 | 
			
		||||
				registration,
 | 
			
		||||
				clientVersion,
 | 
			
		||||
				lastSync);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -66,4 +74,10 @@ public final class LoginCredentials implements Serializable {
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public String getClientVersion() { return clientVersion; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the time stamp of the last synchronization
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public Instant getLastSync() { return lastSync; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
package envoy.data;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.format.DateTimeFormatter;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Represents a unique message with a unique, numeric ID. Further metadata
 | 
			
		||||
@@ -50,14 +49,14 @@ public class Message implements Serializable {
 | 
			
		||||
 | 
			
		||||
	private final long			id, senderID, recipientID;
 | 
			
		||||
	private final boolean		forwarded;
 | 
			
		||||
	private final LocalDateTime	creationDate;
 | 
			
		||||
	private final Instant		creationDate;
 | 
			
		||||
	private final String		text;
 | 
			
		||||
	private final Attachment	attachment;
 | 
			
		||||
 | 
			
		||||
	private LocalDateTime	receivedDate, readDate;
 | 
			
		||||
	private Instant			receivedDate, readDate;
 | 
			
		||||
	private MessageStatus	status;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 1L;
 | 
			
		||||
	private static final long serialVersionUID = 2L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes a {@link Message} with values for all of its properties. The use
 | 
			
		||||
@@ -75,9 +74,9 @@ public class Message implements Serializable {
 | 
			
		||||
	 * @param attachment   the attachment of the message, if present
 | 
			
		||||
	 * @param status       the current {@link MessageStatus} of the message
 | 
			
		||||
	 * @param forwarded    whether this message was forwarded
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	Message(long id, long senderID, long recipientID, LocalDateTime creationDate, LocalDateTime receivedDate, LocalDateTime readDate, String text,
 | 
			
		||||
	Message(long id, long senderID, long recipientID, Instant creationDate, Instant receivedDate, Instant readDate, String text,
 | 
			
		||||
			Attachment attachment, MessageStatus status, boolean forwarded) {
 | 
			
		||||
		this.id				= id;
 | 
			
		||||
		this.senderID		= senderID;
 | 
			
		||||
@@ -115,7 +114,7 @@ public class Message implements Serializable {
 | 
			
		||||
				id,
 | 
			
		||||
				senderID,
 | 
			
		||||
				recipientID,
 | 
			
		||||
				DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss").format(creationDate),
 | 
			
		||||
				creationDate,
 | 
			
		||||
				status,
 | 
			
		||||
				text,
 | 
			
		||||
				forwarded,
 | 
			
		||||
@@ -142,34 +141,34 @@ public class Message implements Serializable {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which this message was created
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getCreationDate() { return creationDate; }
 | 
			
		||||
	public Instant getCreationDate() { return creationDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which the message has been received by the sender
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getReceivedDate() { return receivedDate; }
 | 
			
		||||
	public Instant getReceivedDate() { return receivedDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param receivedDate the date at which the message has been received by the
 | 
			
		||||
	 *                     sender
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void setReceivedDate(LocalDateTime receivedDate) { this.receivedDate = receivedDate; }
 | 
			
		||||
	public void setReceivedDate(Instant receivedDate) { this.receivedDate = receivedDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which the message has been read by the sender
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getReadDate() { return readDate; }
 | 
			
		||||
	public Instant getReadDate() { return readDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param readDate at which the message has been read by the sender
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void setReadDate(LocalDateTime readDate) { this.readDate = readDate; }
 | 
			
		||||
	public void setReadDate(Instant readDate) { this.readDate = readDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the text content of this message
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@@ -23,7 +23,7 @@ public class MessageBuilder {
 | 
			
		||||
 | 
			
		||||
	// Properties with default values
 | 
			
		||||
	private long					id;
 | 
			
		||||
	private LocalDateTime			creationDate, receivedDate, readDate;
 | 
			
		||||
	private Instant					creationDate, receivedDate, readDate;
 | 
			
		||||
	private String					text;
 | 
			
		||||
	private Attachment				attachment;
 | 
			
		||||
	private Message.MessageStatus	status;
 | 
			
		||||
@@ -70,7 +70,7 @@ public class MessageBuilder {
 | 
			
		||||
	public MessageBuilder(Message msg, long recipientID, IDGenerator iDGenerator) {
 | 
			
		||||
		this(msg.getRecipientID(), recipientID, iDGenerator.next());
 | 
			
		||||
		this.attachment		= msg.getAttachment();
 | 
			
		||||
		this.creationDate	= LocalDateTime.now();
 | 
			
		||||
		this.creationDate	= Instant.now();
 | 
			
		||||
		this.forwarded		= true;
 | 
			
		||||
		this.text			= msg.getText();
 | 
			
		||||
		this.status			= MessageStatus.WAITING;
 | 
			
		||||
@@ -83,7 +83,7 @@ public class MessageBuilder {
 | 
			
		||||
	 * <table border="1">
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <td>{@code date}</td>
 | 
			
		||||
	 * <td>{@code LocalDateTime.now()} and {@code null} for {@code receivedDate} and
 | 
			
		||||
	 * <td>{@code Instant.now()} and {@code null} for {@code receivedDate} and
 | 
			
		||||
	 * {@code readDate}</td>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
@@ -113,8 +113,8 @@ public class MessageBuilder {
 | 
			
		||||
	 * <br>
 | 
			
		||||
	 * <table border="1">
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <td>{@code date}</td>
 | 
			
		||||
	 * <td>{@code new Date()}</td>
 | 
			
		||||
	 * <td>{@code time stamp}</td>
 | 
			
		||||
	 * <td>{@code Instant.now()}</td>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <td>{@code text}</td>
 | 
			
		||||
@@ -140,8 +140,8 @@ public class MessageBuilder {
 | 
			
		||||
	 * <br>
 | 
			
		||||
	 * <table border="1">
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <td>{@code date}</td>
 | 
			
		||||
	 * <td>{@code new Date()}</td>
 | 
			
		||||
	 * <td>{@code time stamp}</td>
 | 
			
		||||
	 * <td>{@code Instant.now()}</td>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <tr>
 | 
			
		||||
	 * <td>{@code text}</td>
 | 
			
		||||
@@ -162,7 +162,7 @@ public class MessageBuilder {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void supplyDefaults() {
 | 
			
		||||
		if (creationDate == null) creationDate = LocalDateTime.now();
 | 
			
		||||
		if (creationDate == null) creationDate = Instant.now();
 | 
			
		||||
		if (text == null) text = "";
 | 
			
		||||
		if (status == null) status = MessageStatus.WAITING;
 | 
			
		||||
	}
 | 
			
		||||
@@ -170,9 +170,9 @@ public class MessageBuilder {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param creationDate the creation date of the {@link Message} to create
 | 
			
		||||
	 * @return this {@link MessageBuilder}
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageBuilder setCreationDate(LocalDateTime creationDate) {
 | 
			
		||||
	public MessageBuilder setCreationDate(Instant creationDate) {
 | 
			
		||||
		this.creationDate = creationDate;
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
@@ -180,9 +180,9 @@ public class MessageBuilder {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param receivedDate the received date of the {@link Message} to create
 | 
			
		||||
	 * @return this {@link MessageBuilder}
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageBuilder setReceivedDate(LocalDateTime receivedDate) {
 | 
			
		||||
	public MessageBuilder setReceivedDate(Instant receivedDate) {
 | 
			
		||||
		this.receivedDate = receivedDate;
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
@@ -190,9 +190,9 @@ public class MessageBuilder {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param readDate the read date of the {@link Message} to create
 | 
			
		||||
	 * @return this {@link MessageBuilder}
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageBuilder setReadDate(LocalDateTime readDate) {
 | 
			
		||||
	public MessageBuilder setReadDate(Instant readDate) {
 | 
			
		||||
		this.readDate = readDate;
 | 
			
		||||
		return this;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.event;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
import envoy.data.GroupMessage;
 | 
			
		||||
import envoy.data.Message.MessageStatus;
 | 
			
		||||
@@ -27,9 +27,9 @@ public class GroupMessageStatusChange extends MessageStatusChange {
 | 
			
		||||
	 * @param date     the date at which the MessageStatus change occurred for
 | 
			
		||||
	 *                 this specific member
 | 
			
		||||
	 * @param memberID the ID of the group member that caused the status change
 | 
			
		||||
	 * @since Envoy Common v0.1-beta
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public GroupMessageStatusChange(long id, MessageStatus status, LocalDateTime date, long memberID) {
 | 
			
		||||
	public GroupMessageStatusChange(long id, MessageStatus status, Instant date, long memberID) {
 | 
			
		||||
		super(id, status, date);
 | 
			
		||||
		this.memberID = memberID;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.event;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
 | 
			
		||||
@@ -14,8 +14,8 @@ import envoy.data.Message;
 | 
			
		||||
 */
 | 
			
		||||
public class MessageStatusChange extends Event<Message.MessageStatus> {
 | 
			
		||||
 | 
			
		||||
	private final long	id;
 | 
			
		||||
	private final LocalDateTime	date;
 | 
			
		||||
	private final long		id;
 | 
			
		||||
	private final Instant	date;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 0L;
 | 
			
		||||
 | 
			
		||||
@@ -26,9 +26,9 @@ public class MessageStatusChange extends Event<Message.MessageStatus> {
 | 
			
		||||
	 * @param status the status of the {@link Message} this event is related
 | 
			
		||||
	 *               to
 | 
			
		||||
	 * @param date   the date at which the MessageStatus change occurred
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageStatusChange(long id, Message.MessageStatus status, LocalDateTime date) {
 | 
			
		||||
	public MessageStatusChange(long id, Message.MessageStatus status, Instant date) {
 | 
			
		||||
		super(status);
 | 
			
		||||
		this.id		= id;
 | 
			
		||||
		this.date	= date;
 | 
			
		||||
@@ -40,7 +40,7 @@ public class MessageStatusChange extends Event<Message.MessageStatus> {
 | 
			
		||||
	 * @param message the message from which to build the event
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageStatusChange(Message message) { this(message.getID(), message.getStatus(), LocalDateTime.now()); }
 | 
			
		||||
	public MessageStatusChange(Message message) { this(message.getID(), message.getStatus(), Instant.now()); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the ID of the {@link Message} this event is related to
 | 
			
		||||
@@ -50,9 +50,9 @@ public class MessageStatusChange extends Event<Message.MessageStatus> {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which the status change occurred
 | 
			
		||||
	 * @since Envoy Common v0.2-alpha
 | 
			
		||||
	 * @since Envoy Common v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getDate() { return date; }
 | 
			
		||||
	public Instant getDate() { return date; }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() { return String.format("MessageStatusChange[id=%d,status=%s,date=%s]", id, value, date); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.server.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
@@ -28,7 +28,7 @@ public abstract class Contact {
 | 
			
		||||
	protected String	name;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "creation_date")
 | 
			
		||||
	private LocalDateTime creationDate;
 | 
			
		||||
	private Instant creationDate;
 | 
			
		||||
 | 
			
		||||
	@ManyToMany(fetch = FetchType.EAGER)
 | 
			
		||||
	protected Set<Contact> contacts;
 | 
			
		||||
@@ -92,15 +92,15 @@ public abstract class Contact {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the creationDate
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getCreationDate() { return creationDate; }
 | 
			
		||||
	public Instant getCreationDate() { return creationDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param creationDate the creationDate to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void setCreationDate(LocalDateTime creationDate) { this.creationDate = creationDate; }
 | 
			
		||||
	public void setCreationDate(Instant creationDate) { this.creationDate = creationDate; }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public String toString() { return String.format("%s[id=%d,name=%s, %d contact(s)]", getClass().getSimpleName(), id, name, contacts.size()); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.server.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +39,7 @@ public class GroupMessage extends Message {
 | 
			
		||||
	private Map<Long, envoy.data.Message.MessageStatus> memberMessageStatus;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "last_status_change_date")
 | 
			
		||||
	protected LocalDateTime lastStatusChangeDate;
 | 
			
		||||
	protected Instant lastStatusChangeDate;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * The constructor for a database object.
 | 
			
		||||
@@ -55,9 +55,9 @@ public class GroupMessage extends Message {
 | 
			
		||||
	 *                             into a
 | 
			
		||||
	 *                             database {@link GroupMessage}
 | 
			
		||||
	 * @param lastStatusChangeDate the time stamp to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public GroupMessage(envoy.data.GroupMessage groupMessage, LocalDateTime lastStatusChangeDate) {
 | 
			
		||||
	public GroupMessage(envoy.data.GroupMessage groupMessage, Instant lastStatusChangeDate) {
 | 
			
		||||
		super(groupMessage);
 | 
			
		||||
		memberMessageStatus			= groupMessage.getMemberStatuses();
 | 
			
		||||
		this.lastStatusChangeDate	= lastStatusChangeDate;
 | 
			
		||||
@@ -92,13 +92,13 @@ public class GroupMessage extends Message {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which one of the member statuses changed last
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getLastStatusChangeDate() { return lastStatusChangeDate; }
 | 
			
		||||
	public Instant getLastStatusChangeDate() { return lastStatusChangeDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param date the date to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void setLastStatusChangeDate(LocalDateTime date) { lastStatusChangeDate = date; }
 | 
			
		||||
	public void setLastStatusChangeDate(Instant date) { lastStatusChangeDate = date; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package envoy.server.data;
 | 
			
		||||
 | 
			
		||||
import static envoy.data.Message.MessageStatus.*;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
 | 
			
		||||
@@ -55,13 +55,13 @@ public class Message {
 | 
			
		||||
	protected Contact recipient;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "creation_date")
 | 
			
		||||
	protected LocalDateTime creationDate;
 | 
			
		||||
	protected Instant creationDate;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "received_date")
 | 
			
		||||
	protected LocalDateTime receivedDate;
 | 
			
		||||
	protected Instant receivedDate;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "read_date")
 | 
			
		||||
	protected LocalDateTime readDate;
 | 
			
		||||
	protected Instant readDate;
 | 
			
		||||
 | 
			
		||||
	protected String							text;
 | 
			
		||||
	protected envoy.data.Message.MessageStatus	status;
 | 
			
		||||
@@ -134,7 +134,7 @@ public class Message {
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void received() {
 | 
			
		||||
		receivedDate	= LocalDateTime.now();
 | 
			
		||||
		receivedDate	= Instant.now();
 | 
			
		||||
		status			= RECEIVED;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -145,7 +145,7 @@ public class Message {
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void read() {
 | 
			
		||||
		readDate	= LocalDateTime.now();
 | 
			
		||||
		readDate	= Instant.now();
 | 
			
		||||
		status		= READ;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -190,43 +190,43 @@ public class Message {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which a {link envoy.data.Message} has been created
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getCreationDate() { return creationDate; }
 | 
			
		||||
	public Instant getCreationDate() { return creationDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param creationDate the creation date to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 * @see Message#getCreationDate()
 | 
			
		||||
	 */
 | 
			
		||||
	public void setCreationDate(LocalDateTime creationDate) { this.creationDate = creationDate; }
 | 
			
		||||
	public void setCreationDate(Instant creationDate) { this.creationDate = creationDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which a {link envoy.data.Message} has been received by
 | 
			
		||||
	 *         the server
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getReceivedDate() { return receivedDate; }
 | 
			
		||||
	public Instant getReceivedDate() { return receivedDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param receivedDate the received date to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 * @see Message#getReceivedDate()
 | 
			
		||||
	 */
 | 
			
		||||
	public void setReceivedDate(LocalDateTime receivedDate) { this.receivedDate = receivedDate; }
 | 
			
		||||
	public void setReceivedDate(Instant receivedDate) { this.receivedDate = receivedDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the date at which a {link envoy.data.Message} has been read
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getReadDate() { return readDate; }
 | 
			
		||||
	public Instant getReadDate() { return readDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param readDate the read date to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 * @see Message#getReadDate()
 | 
			
		||||
	 */
 | 
			
		||||
	public void setReadDate(LocalDateTime readDate) { this.readDate = readDate; }
 | 
			
		||||
	public void setReadDate(Instant readDate) { this.readDate = readDate; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the status of a {link envoy.data.Message}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.server.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.EntityManager;
 | 
			
		||||
@@ -38,7 +38,7 @@ public class PersistenceManager {
 | 
			
		||||
				.getOnlineUsers()
 | 
			
		||||
				.stream()
 | 
			
		||||
				.map(this::getUserByID)
 | 
			
		||||
				.forEach(user -> { user.setStatus(UserStatus.OFFLINE); user.setLastSeen(LocalDateTime.now()); entityManager.merge(user); });
 | 
			
		||||
				.forEach(user -> { user.setStatus(UserStatus.OFFLINE); user.setLastSeen(Instant.now()); entityManager.merge(user); });
 | 
			
		||||
			transaction.commit();
 | 
			
		||||
		}));
 | 
			
		||||
	}
 | 
			
		||||
@@ -182,31 +182,29 @@ public class PersistenceManager {
 | 
			
		||||
	 * Returns all messages received while being offline or the ones that have
 | 
			
		||||
	 * changed.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param user the user who wants to receive his unread messages
 | 
			
		||||
	 * @param user     the user who wants to receive his unread messages
 | 
			
		||||
	 * @param lastSync the time stamp of the last synchronization
 | 
			
		||||
	 * @return all messages that the client does not yet have (unread messages)
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public List<Message> getPendingMessages(User user) {
 | 
			
		||||
		return entityManager
 | 
			
		||||
			.createNamedQuery(Message.getPending)
 | 
			
		||||
			.setParameter("user", user)
 | 
			
		||||
			.setParameter("lastSeen", user.getLastSeen())
 | 
			
		||||
			.getResultList();
 | 
			
		||||
	public List<Message> getPendingMessages(User user, Instant lastSync) {
 | 
			
		||||
		return entityManager.createNamedQuery(Message.getPending).setParameter("user", user).setParameter("lastSeen", lastSync).getResultList();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns all groupMessages received while being offline or the ones that have
 | 
			
		||||
	 * changed.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param user the user who wants to receive his unread groupMessages
 | 
			
		||||
	 * @param user     the user who wants to receive his unread groupMessages
 | 
			
		||||
	 * @param lastSync the time stamp of the last synchronization
 | 
			
		||||
	 * @return all groupMessages that the client does not yet have (unread
 | 
			
		||||
	 *         groupMessages)
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public List<GroupMessage> getPendingGroupMessages(User user) {
 | 
			
		||||
	public List<GroupMessage> getPendingGroupMessages(User user, Instant lastSync) {
 | 
			
		||||
		return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg)
 | 
			
		||||
			.setParameter("userId", user.getID())
 | 
			
		||||
			.setParameter("lastSeen", user.getLastSeen())
 | 
			
		||||
			.setParameter("lastSeen", lastSync)
 | 
			
		||||
			.getResultList();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -221,8 +219,7 @@ public class PersistenceManager {
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public List<User> searchUsers(String searchPhrase, long userId) {
 | 
			
		||||
		return entityManager.createNamedQuery(
 | 
			
		||||
				User.searchByName)
 | 
			
		||||
		return entityManager.createNamedQuery(User.searchByName)
 | 
			
		||||
			.setParameter("searchPhrase", searchPhrase + "%")
 | 
			
		||||
			.setParameter("context", getUserByID(userId))
 | 
			
		||||
			.getResultList();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.server.data;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +66,7 @@ public class User extends Contact {
 | 
			
		||||
	private String passwordHash;
 | 
			
		||||
 | 
			
		||||
	@Column(name = "last_seen")
 | 
			
		||||
	private LocalDateTime lastSeen;
 | 
			
		||||
	private Instant lastSeen;
 | 
			
		||||
 | 
			
		||||
	private UserStatus status;
 | 
			
		||||
 | 
			
		||||
@@ -92,15 +92,15 @@ public class User extends Contact {
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the last date the user has been online
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public LocalDateTime getLastSeen() { return lastSeen; }
 | 
			
		||||
	public Instant getLastSeen() { return lastSeen; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param lastSeen the latest date at which the user has been online to set
 | 
			
		||||
	 * @since Envoy Server Standalone v0.1-alpha
 | 
			
		||||
	 * @since Envoy Server Standalone v0.2-beta
 | 
			
		||||
	 */
 | 
			
		||||
	public void setLastSeen(LocalDateTime lastSeen) { this.lastSeen = lastSeen; }
 | 
			
		||||
	public void setLastSeen(Instant lastSeen) { this.lastSeen = lastSeen; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the status
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package envoy.server.net;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +52,7 @@ public class ConnectionManager implements ISocketIdListener {
 | 
			
		||||
			// Notify contacts of this users offline-going
 | 
			
		||||
			envoy.server.data.User user = PersistenceManager.getInstance().getUserByID(getUserIDBySocketID(socketID));
 | 
			
		||||
			user.setStatus(UserStatus.OFFLINE);
 | 
			
		||||
			user.setLastSeen(LocalDateTime.now());
 | 
			
		||||
			user.setLastSeen(Instant.now());
 | 
			
		||||
			UserStatusChangeProcessor.updateUserStatus(user);
 | 
			
		||||
 | 
			
		||||
			// Remove the socket
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package envoy.server.processors;
 | 
			
		||||
 | 
			
		||||
import static envoy.data.Message.MessageStatus.*;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
@@ -56,7 +56,7 @@ public class GroupMessageProcessor implements ObjectProcessor<GroupMessage> {
 | 
			
		||||
				groupMessage);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			PersistenceManager.getInstance().addMessage(new envoy.server.data.GroupMessage(groupMessage, LocalDateTime.now()));
 | 
			
		||||
			PersistenceManager.getInstance().addMessage(new envoy.server.data.GroupMessage(groupMessage, Instant.now()));
 | 
			
		||||
		} catch (EntityExistsException e) {
 | 
			
		||||
			logger.warning("Received a groupMessage with an ID that already exists");
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package envoy.server.processors;
 | 
			
		||||
 | 
			
		||||
import static envoy.data.Message.MessageStatus.READ;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.logging.Level;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
@@ -42,7 +42,7 @@ public class GroupMessageStatusChangeProcessor implements ObjectProcessor<GroupM
 | 
			
		||||
 | 
			
		||||
		// Apply the status change
 | 
			
		||||
		gmsg.getMemberMessageStatus().replace(statusChange.getMemberID(), statusChange.get());
 | 
			
		||||
		gmsg.setLastStatusChangeDate(LocalDateTime.now());
 | 
			
		||||
		gmsg.setLastStatusChangeDate(Instant.now());
 | 
			
		||||
 | 
			
		||||
		// Notifying the other members about the status change
 | 
			
		||||
		final var userID = connectionManager.getUserIDBySocketID(socketID);
 | 
			
		||||
@@ -59,7 +59,7 @@ public class GroupMessageStatusChangeProcessor implements ObjectProcessor<GroupM
 | 
			
		||||
 | 
			
		||||
			// Notify online members about the status change
 | 
			
		||||
			writeProxy.writeToOnlineContacts(gmsg.getRecipient().getContacts(),
 | 
			
		||||
					new MessageStatusChange(gmsg.getID(), gmsg.getStatus(), LocalDateTime.now()));
 | 
			
		||||
					new MessageStatusChange(gmsg.getID(), gmsg.getStatus(), Instant.now()));
 | 
			
		||||
		}
 | 
			
		||||
		persistenceManager.updateMessage(gmsg);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ import static envoy.data.Message.MessageStatus.*;
 | 
			
		||||
import static envoy.data.User.UserStatus.ONLINE;
 | 
			
		||||
import static envoy.event.HandshakeRejection.*;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -47,7 +47,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
	@Override
 | 
			
		||||
	public void process(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) {
 | 
			
		||||
 | 
			
		||||
		// Cache this write proxy for user-independant notifications
 | 
			
		||||
		// Cache this write proxy for user-independent notifications
 | 
			
		||||
		UserStatusChangeProcessor.setWriteProxy(writeProxy);
 | 
			
		||||
 | 
			
		||||
		if (!VersionUtil.verifyCompatibility(credentials.getClientVersion())) {
 | 
			
		||||
@@ -98,7 +98,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
				// Creation of a new user
 | 
			
		||||
				user = new User();
 | 
			
		||||
				user.setName(credentials.getIdentifier());
 | 
			
		||||
				user.setLastSeen(LocalDateTime.now());
 | 
			
		||||
				user.setLastSeen(Instant.now());
 | 
			
		||||
				user.setStatus(ONLINE);
 | 
			
		||||
				user.setPasswordHash(PasswordUtil.hash(credentials.getPassword()));
 | 
			
		||||
				user.setContacts(new HashSet<>());
 | 
			
		||||
@@ -117,7 +117,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
		// Complete the handshake
 | 
			
		||||
		writeProxy.write(socketID, user.toCommon());
 | 
			
		||||
 | 
			
		||||
		final var pendingMessages = PersistenceManager.getInstance().getPendingMessages(user);
 | 
			
		||||
		final var pendingMessages = PersistenceManager.getInstance().getPendingMessages(user, credentials.getLastSync());
 | 
			
		||||
		pendingMessages.removeIf(GroupMessage.class::isInstance);
 | 
			
		||||
		logger.fine("Sending " + pendingMessages.size() + " pending messages to " + user + "...");
 | 
			
		||||
 | 
			
		||||
@@ -138,7 +138,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
			} else writeProxy.write(socketID, new MessageStatusChange(msgCommon));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance().getPendingGroupMessages(user);
 | 
			
		||||
		List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance().getPendingGroupMessages(user, credentials.getLastSync());
 | 
			
		||||
		logger.fine("Sending " + pendingGroupMessages.size() + " pending group messages to " + user + "...");
 | 
			
		||||
 | 
			
		||||
		for (var gmsg : pendingGroupMessages) {
 | 
			
		||||
@@ -148,13 +148,13 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
			if (gmsg.getMemberMessageStatus().get(user.getID()) == SENT) {
 | 
			
		||||
				gmsg.getMemberMessageStatus().replace(user.getID(), RECEIVED);
 | 
			
		||||
 | 
			
		||||
				gmsg.setLastStatusChangeDate(LocalDateTime.now());
 | 
			
		||||
				gmsg.setLastStatusChangeDate(Instant.now());
 | 
			
		||||
 | 
			
		||||
				writeProxy.write(socketID, gmsgCommon);
 | 
			
		||||
 | 
			
		||||
				// Notify all online group members about the status change
 | 
			
		||||
				writeProxy.writeToOnlineContacts(gmsg.getRecipient().getContacts(),
 | 
			
		||||
						new GroupMessageStatusChange(gmsg.getID(), RECEIVED, LocalDateTime
 | 
			
		||||
						new GroupMessageStatusChange(gmsg.getID(), RECEIVED, Instant
 | 
			
		||||
							.now(),
 | 
			
		||||
								connectionManager.getUserIDBySocketID(socketID)));
 | 
			
		||||
 | 
			
		||||
@@ -163,7 +163,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
			
		||||
 | 
			
		||||
					// Notify online members about the status change
 | 
			
		||||
					writeProxy.writeToOnlineContacts(gmsg.getRecipient().getContacts(),
 | 
			
		||||
							new MessageStatusChange(gmsg.getID(), gmsg.getStatus(), LocalDateTime.now()));
 | 
			
		||||
							new MessageStatusChange(gmsg.getID(), gmsg.getStatus(), Instant.now()));
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				PersistenceManager.getInstance().updateMessage(gmsg);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user