Merge branch 'develop' into f/logging
This commit is contained in:
		@@ -1,374 +1,304 @@
 | 
			
		||||
package envoy.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.ObjectInputStream;
 | 
			
		||||
import java.io.ObjectOutputStream;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import javax.xml.datatype.DatatypeConfigurationException;
 | 
			
		||||
import javax.xml.datatype.DatatypeFactory;
 | 
			
		||||
 | 
			
		||||
import envoy.exception.EnvoyException;
 | 
			
		||||
import envoy.schema.Message;
 | 
			
		||||
import envoy.schema.Message.Metadata.MessageState;
 | 
			
		||||
import envoy.schema.ObjectFactory;
 | 
			
		||||
import envoy.schema.Sync;
 | 
			
		||||
import envoy.schema.User;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>LocalDB.java</strong><br>
 | 
			
		||||
 * Created: <strong>27.10.2019</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @author Maximilian Käfer
 | 
			
		||||
 * @since Envoy v0.1-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class LocalDB {
 | 
			
		||||
	private File			localDB;
 | 
			
		||||
	private User			sender;
 | 
			
		||||
	private List<Chat>		chats			= new ArrayList<>();
 | 
			
		||||
	private ObjectFactory	objectFactory	= new ObjectFactory();
 | 
			
		||||
	private DatatypeFactory	datatypeFactory;
 | 
			
		||||
 | 
			
		||||
	private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName());
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Constructs an empty local database.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param client the user that is logged in with this client
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
 | 
			
		||||
	public LocalDB(User sender) {
 | 
			
		||||
		this.sender = sender;
 | 
			
		||||
		try {
 | 
			
		||||
			datatypeFactory = DatatypeFactory.newInstance();
 | 
			
		||||
		} catch (DatatypeConfigurationException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes the local database and fills it with values
 | 
			
		||||
	 * if the user has already sent or received messages.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param localDBDir the directory where we wish to save/load the database from.
 | 
			
		||||
	 * @throws EnvoyException if the directory selected is not an actual directory.
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
	public void initializeDBFile(File localDBDir) throws EnvoyException {
 | 
			
		||||
		if (localDBDir.exists() && !localDBDir.isDirectory()) throw new EnvoyException(
 | 
			
		||||
				String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath()));
 | 
			
		||||
		localDB = new File(localDBDir, sender.getID() + ".db");
 | 
			
		||||
		if (localDB.exists()) loadFromLocalDB();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Saves the database into a file for future use.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws IOException if something went wrong during saving
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
	public void saveToLocalDB() {
 | 
			
		||||
		try {
 | 
			
		||||
			localDB.getParentFile().mkdirs();
 | 
			
		||||
			localDB.createNewFile();
 | 
			
		||||
		} catch (IOException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
			logger.warning("unable to save the messages");
 | 
			
		||||
		}
 | 
			
		||||
		try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) {
 | 
			
		||||
			out.writeObject(chats);
 | 
			
		||||
		} catch (IOException ex) {
 | 
			
		||||
			ex.printStackTrace();
 | 
			
		||||
			logger.warning("unable to save the messages");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Loads all chats saved by Envoy for the client user.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws EnvoyException if something fails while loading.
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	private void loadFromLocalDB() throws EnvoyException {
 | 
			
		||||
		try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) {
 | 
			
		||||
			Object obj = in.readObject();
 | 
			
		||||
			if (obj instanceof ArrayList<?>) chats = (ArrayList<Chat>) obj;
 | 
			
		||||
		} catch (ClassNotFoundException | IOException e) {
 | 
			
		||||
			throw new EnvoyException(e);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a {@link Message} object serializable to XML.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param textContent The content (text) of the message
 | 
			
		||||
	 * @return prepared {@link Message} object
 | 
			
		||||
	 */
 | 
			
		||||
	public Message createMessage(String textContent, User recipient) {
 | 
			
		||||
		Message.Metadata metaData = objectFactory.createMessageMetadata();
 | 
			
		||||
		metaData.setSender(sender.getID());
 | 
			
		||||
		metaData.setRecipient(recipient.getID());
 | 
			
		||||
		metaData.setState(MessageState.WAITING);
 | 
			
		||||
		metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString()));
 | 
			
		||||
 | 
			
		||||
		Message.Content content = objectFactory.createMessageContent();
 | 
			
		||||
		content.setType("text");
 | 
			
		||||
		content.setText(textContent);
 | 
			
		||||
 | 
			
		||||
		Message message = objectFactory.createMessage();
 | 
			
		||||
		message.setMetadata(metaData);
 | 
			
		||||
		message.getContent().add(content);
 | 
			
		||||
 | 
			
		||||
		return message;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private Sync	unreadMessagesSync	= objectFactory.createSync();
 | 
			
		||||
	public Sync		sync				= objectFactory.createSync();
 | 
			
		||||
	public Sync		readMessages		= objectFactory.createSync();
 | 
			
		||||
 | 
			
		||||
	public Sync fillSync(long userId) {
 | 
			
		||||
 | 
			
		||||
		addWaitingMessagesToSync();
 | 
			
		||||
 | 
			
		||||
		getSentStateMessagesFromLocalDB();
 | 
			
		||||
		for (int i = 0; i < readMessages.getMessages().size(); i++) {
 | 
			
		||||
			sync.getMessages().add(readMessages.getMessages().get(i));
 | 
			
		||||
		}
 | 
			
		||||
		readMessages.getMessages().clear();
 | 
			
		||||
 | 
			
		||||
		logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size()));
 | 
			
		||||
		return sync;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void applySync(Sync returnSync) {
 | 
			
		||||
		for (int i = 0; i < returnSync.getMessages().size(); i++) {
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) {
 | 
			
		||||
				// Update Local Messages with State WAITING (add Message ID and change State to
 | 
			
		||||
				// SENT)
 | 
			
		||||
				for (int j = 0; j < sync.getMessages().size(); j++) {
 | 
			
		||||
					if (j == i) {
 | 
			
		||||
						sync.getMessages()
 | 
			
		||||
							.get(j)
 | 
			
		||||
							.getMetadata()
 | 
			
		||||
							.setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId());
 | 
			
		||||
						sync.getMessages()
 | 
			
		||||
							.get(j)
 | 
			
		||||
							.getMetadata()
 | 
			
		||||
							.setState(returnSync.getMessages().get(j).getMetadata().getState());
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getSender() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
				// these are the unread Messages from the server
 | 
			
		||||
				unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i));
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getSender() == 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
				// Update Messages in localDB to state RECEIVED
 | 
			
		||||
				for (int j = 0; j < getChats().size(); j++) {
 | 
			
		||||
					if (getChats().get(j)
 | 
			
		||||
						.getRecipient()
 | 
			
		||||
						.getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) {
 | 
			
		||||
						for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) {
 | 
			
		||||
							if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync
 | 
			
		||||
								.getMessages()
 | 
			
		||||
								.get(i)
 | 
			
		||||
								.getMetadata()
 | 
			
		||||
								.getMessageId()) {
 | 
			
		||||
								// Update Message in LocalDB
 | 
			
		||||
								getChats().get(j)
 | 
			
		||||
									.getModel()
 | 
			
		||||
									.get(k)
 | 
			
		||||
									.getMetadata()
 | 
			
		||||
									.setState(returnSync.getMessages().get(j).getMetadata().getState());
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) {
 | 
			
		||||
				// Update local Messages to state READ
 | 
			
		||||
				logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId()
 | 
			
		||||
						+ "was initialized to be set to READ in localDB.");
 | 
			
		||||
				for (int j = 0; j < getChats().size(); j++) {
 | 
			
		||||
					if (getChats().get(j)
 | 
			
		||||
						.getRecipient()
 | 
			
		||||
						.getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) {
 | 
			
		||||
						logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected.");
 | 
			
		||||
						for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) {
 | 
			
		||||
							if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync
 | 
			
		||||
								.getMessages()
 | 
			
		||||
								.get(i)
 | 
			
		||||
								.getMetadata()
 | 
			
		||||
								.getMessageId()) {
 | 
			
		||||
								logger.info("Message with ID: "
 | 
			
		||||
										+ getChats().get(j).getModel().get(k).getMetadata().getMessageId()
 | 
			
		||||
										+ "was selected.");
 | 
			
		||||
								getChats().get(j)
 | 
			
		||||
									.getModel()
 | 
			
		||||
									.get(k)
 | 
			
		||||
									.getMetadata()
 | 
			
		||||
									.setState(returnSync.getMessages().get(i).getMetadata().getState());
 | 
			
		||||
								logger.info("Message State is now: "
 | 
			
		||||
										+ getChats().get(j).getModel().get(k).getMetadata().getState().toString());
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Updating UserStatus of all users in LocalDB
 | 
			
		||||
		for (int j = 0; j < returnSync.getUsers().size(); j++) {
 | 
			
		||||
			for (int k = 0; k < getChats().size(); k++) {
 | 
			
		||||
				if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) {
 | 
			
		||||
 | 
			
		||||
					getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus());
 | 
			
		||||
					logger.info(getChats().get(k).getRecipient().getStatus().toString());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sync.getMessages().clear();
 | 
			
		||||
		sync.getUsers().clear();
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds a message to the "sync" Sync object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param message
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addMessageToSync(Message message) { sync.getMessages().add(message); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds a user to the {@code sync} {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param user
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addUserToSync(User user) { sync.getUsers().add(user); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds the unread messages returned from the server in the latest sync to the
 | 
			
		||||
	 * right chats in the LocalDB.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param localDB
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addUnreadMessagesToLocalDB() {
 | 
			
		||||
		Sync unreadMessages = unreadMessagesSync;
 | 
			
		||||
		for (int i = 0; i < unreadMessages.getMessages().size(); i++)
 | 
			
		||||
			for (int j = 0; j < getChats().size(); j++)
 | 
			
		||||
				if (getChats().get(j)
 | 
			
		||||
					.getRecipient()
 | 
			
		||||
					.getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) {
 | 
			
		||||
					getChats().get(j).appendMessage(unreadMessages.getMessages().get(i));
 | 
			
		||||
				}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Gets all messages with state SENT from the LocalDB and adds them to the
 | 
			
		||||
	 * "sync" Sync object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param localDB
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void getSentStateMessagesFromLocalDB() {
 | 
			
		||||
		for (int i = 0; i < getChats().size(); i++) {
 | 
			
		||||
			for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) {
 | 
			
		||||
				if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.SENT) {
 | 
			
		||||
					addMessageToSync(getChats().get(i).getModel().get(j));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Changes all messages with State RECEIVED of a specific chat to State READ.
 | 
			
		||||
	 * <br>
 | 
			
		||||
	 * Adds these Messages to the {@code readMessages} {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param currentChat
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void setMessagesToRead(Chat currentChat) {
 | 
			
		||||
		for (int i = currentChat.getModel().size() - 1; i >= 0; --i)
 | 
			
		||||
			if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID())
 | 
			
		||||
				if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
					currentChat.getModel().get(i).getMetadata().setState(MessageState.READ);
 | 
			
		||||
					readMessages.getMessages().add(currentChat.getModel().get(i));
 | 
			
		||||
				} else break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds a message with State WAITING to a specific chat in the LocalDB.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param message
 | 
			
		||||
	 * @param currentChat
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addWaitingMessageToLocalDB(Message message, Chat currentChat) { currentChat.appendMessage(message); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds all messages with State WAITING from the {@link LocalDB} to the Sync.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param localDB
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addWaitingMessagesToSync() {
 | 
			
		||||
		for (int i = 0; i < getChats().size(); i++) {
 | 
			
		||||
			for (int j = 0; j < getChats().get(i).getModel().getSize(); j++) {
 | 
			
		||||
				if (getChats().get(i).getModel().get(j).getMetadata().getState() == MessageState.WAITING) {
 | 
			
		||||
					// addMessageToSync(localDB.getChats().get(i).getModel().get(j));
 | 
			
		||||
					logger.info("Got Waiting Message");
 | 
			
		||||
					sync.getMessages().add(0, getChats().get(i).getModel().get(j));
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clears the {@code unreadMessagesSync} {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return all saves {@link Chat} objects that list the client user as the
 | 
			
		||||
	 *         client
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
	public List<Chat> getChats() { return chats; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the User who initialised the local Database
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public User getUser() { return sender; }
 | 
			
		||||
}
 | 
			
		||||
package envoy.client;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.ObjectInputStream;
 | 
			
		||||
import java.io.ObjectOutputStream;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import javax.xml.datatype.DatatypeConfigurationException;
 | 
			
		||||
import javax.xml.datatype.DatatypeFactory;
 | 
			
		||||
 | 
			
		||||
import envoy.exception.EnvoyException;
 | 
			
		||||
import envoy.schema.Message;
 | 
			
		||||
import envoy.schema.Message.Metadata.MessageState;
 | 
			
		||||
import envoy.schema.ObjectFactory;
 | 
			
		||||
import envoy.schema.Sync;
 | 
			
		||||
import envoy.schema.User;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>LocalDB.java</strong><br>
 | 
			
		||||
 * Created: <strong>27.10.2019</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @author Maximilian Käfer
 | 
			
		||||
 * @since Envoy v0.1-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class LocalDB {
 | 
			
		||||
 | 
			
		||||
	private File			localDB;
 | 
			
		||||
	private User			sender;
 | 
			
		||||
	private List<Chat>		chats			= new ArrayList<>();
 | 
			
		||||
	private ObjectFactory	objectFactory	= new ObjectFactory();
 | 
			
		||||
	private DatatypeFactory	datatypeFactory;
 | 
			
		||||
 | 
			
		||||
	private static final Logger logger = Logger.getLogger(LocalDB.class.getSimpleName());
 | 
			
		||||
	
 | 
			
		||||
	private Sync	unreadMessagesSync	= objectFactory.createSync();
 | 
			
		||||
	private Sync	sync				= objectFactory.createSync();
 | 
			
		||||
	private Sync	readMessages		= objectFactory.createSync();
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Constructs an empty local database.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param client the user that is logged in with this client
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	public LocalDB(User sender) {
 | 
			
		||||
		this.sender = sender;
 | 
			
		||||
		try {
 | 
			
		||||
			datatypeFactory = DatatypeFactory.newInstance();
 | 
			
		||||
		} catch (DatatypeConfigurationException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes the local database and fills it with values
 | 
			
		||||
	 * if the user has already sent or received messages.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param localDBDir the directory where we wish to save/load the database from.
 | 
			
		||||
	 * @throws EnvoyException if the directory selected is not an actual directory.
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void initializeDBFile(File localDBDir) throws EnvoyException {
 | 
			
		||||
		if (localDBDir.exists() && !localDBDir.isDirectory())
 | 
			
		||||
			throw new EnvoyException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath()));
 | 
			
		||||
		localDB = new File(localDBDir, sender.getID() + ".db");
 | 
			
		||||
		if (localDB.exists()) loadFromLocalDB();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Saves the database into a file for future use.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws IOException if something went wrong during saving
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void saveToLocalDB() {
 | 
			
		||||
		try {
 | 
			
		||||
			localDB.getParentFile().mkdirs();
 | 
			
		||||
			localDB.createNewFile();
 | 
			
		||||
		} catch (IOException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
			logger.warning("unable to save the messages");
 | 
			
		||||
		}
 | 
			
		||||
		try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) {
 | 
			
		||||
			out.writeObject(chats);
 | 
			
		||||
		} catch (IOException ex) {
 | 
			
		||||
			ex.printStackTrace();
 | 
			
		||||
			logger.warning("unable to save the messages");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Loads all chats saved by Envoy for the client user.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @throws EnvoyException if something fails while loading.
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	private void loadFromLocalDB() throws EnvoyException {
 | 
			
		||||
		try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(localDB))) {
 | 
			
		||||
			Object obj = in.readObject();
 | 
			
		||||
			if (obj instanceof ArrayList<?>) chats = (ArrayList<Chat>) obj;
 | 
			
		||||
		} catch (ClassNotFoundException | IOException e) {
 | 
			
		||||
			throw new EnvoyException(e);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Creates a {@link Message} object serializable to XML.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param textContent The content (text) of the message
 | 
			
		||||
	 * @return prepared {@link Message} object
 | 
			
		||||
	 */
 | 
			
		||||
	public Message createMessage(String textContent, User recipient) {
 | 
			
		||||
		Message.Metadata metaData = objectFactory.createMessageMetadata();
 | 
			
		||||
		metaData.setSender(sender.getID());
 | 
			
		||||
		metaData.setRecipient(recipient.getID());
 | 
			
		||||
		metaData.setState(MessageState.WAITING);
 | 
			
		||||
		metaData.setDate(datatypeFactory.newXMLGregorianCalendar(Instant.now().toString()));
 | 
			
		||||
 | 
			
		||||
		Message.Content content = objectFactory.createMessageContent();
 | 
			
		||||
		content.setType("text");
 | 
			
		||||
		content.setText(textContent);
 | 
			
		||||
 | 
			
		||||
		Message message = objectFactory.createMessage();
 | 
			
		||||
		message.setMetadata(metaData);
 | 
			
		||||
		message.getContent().add(content);
 | 
			
		||||
 | 
			
		||||
		return message;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public Sync fillSync(long userId) {
 | 
			
		||||
		addWaitingMessagesToSync();
 | 
			
		||||
 | 
			
		||||
		sync.getMessages().addAll(readMessages.getMessages());
 | 
			
		||||
		readMessages.getMessages().clear();
 | 
			
		||||
 | 
			
		||||
		logger.info(String.format("Filled sync with %d messages.", sync.getMessages().size()));
 | 
			
		||||
		return sync;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void applySync(Sync returnSync) {
 | 
			
		||||
		for (int i = 0; i < returnSync.getMessages().size(); i++) {
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.SENT) {
 | 
			
		||||
				// Update Local Messages with State WAITING (add Message ID and change State to
 | 
			
		||||
				// SENT)
 | 
			
		||||
				for (int j = 0; j < sync.getMessages().size(); j++) {
 | 
			
		||||
					if (j == i) {
 | 
			
		||||
						sync.getMessages().get(j).getMetadata().setMessageId(returnSync.getMessages().get(j).getMetadata().getMessageId());
 | 
			
		||||
						sync.getMessages().get(j).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState());
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
				// these are the unread Messages from the server
 | 
			
		||||
				unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i));
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0 && returnSync.getMessages().get(i).getMetadata().getSender() == 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
				// Update Messages in localDB to state RECEIVED
 | 
			
		||||
				for (int j = 0; j < getChats().size(); j++) {
 | 
			
		||||
					if (getChats().get(j).getRecipient().getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) {
 | 
			
		||||
						for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) {
 | 
			
		||||
							if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages()
 | 
			
		||||
								.get(i)
 | 
			
		||||
								.getMetadata()
 | 
			
		||||
								.getMessageId()) {
 | 
			
		||||
								// Update Message in LocalDB
 | 
			
		||||
								getChats().get(j).getModel().get(k).getMetadata().setState(returnSync.getMessages().get(j).getMetadata().getState());
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0
 | 
			
		||||
					&& returnSync.getMessages().get(i).getMetadata().getState() == MessageState.READ) {
 | 
			
		||||
				// Update local Messages to state READ
 | 
			
		||||
				logger.info("Message with ID: " + returnSync.getMessages().get(i).getMetadata().getMessageId()
 | 
			
		||||
						+ "was initialized to be set to READ in localDB.");
 | 
			
		||||
				for (int j = 0; j < getChats().size(); j++) {
 | 
			
		||||
					if (getChats().get(j)
 | 
			
		||||
						.getRecipient()
 | 
			
		||||
						.getID() == returnSync.getMessages().get(i).getMetadata().getRecipient()) {
 | 
			
		||||
						logger.info("Chat with: " + getChats().get(j).getRecipient().getID() + "was selected.");
 | 
			
		||||
						for (int k = 0; k < getChats().get(j).getModel().getSize(); k++) {
 | 
			
		||||
							if (getChats().get(j).getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages()
 | 
			
		||||
								.get(i)
 | 
			
		||||
								.getMetadata()
 | 
			
		||||
								.getMessageId()) {
 | 
			
		||||
								logger.info("Message with ID: "
 | 
			
		||||
										+ getChats().get(j).getModel().get(k).getMetadata().getMessageId()
 | 
			
		||||
										+ "was selected.");
 | 
			
		||||
								getChats().get(j)
 | 
			
		||||
									.getModel()
 | 
			
		||||
									.get(k)
 | 
			
		||||
									.getMetadata()
 | 
			
		||||
									.setState(returnSync.getMessages().get(i).getMetadata().getState());
 | 
			
		||||
								logger.info("Message State is now: "
 | 
			
		||||
										+ getChats().get(j).getModel().get(k).getMetadata().getState().toString());
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Updating UserStatus of all users in LocalDB
 | 
			
		||||
		for (int j = 0; j < returnSync.getUsers().size(); j++) {
 | 
			
		||||
			for (int k = 0; k < getChats().size(); k++) {
 | 
			
		||||
				if (getChats().get(k).getRecipient().getID() == returnSync.getUsers().get(j).getID()) {
 | 
			
		||||
 | 
			
		||||
					getChats().get(k).getRecipient().setStatus(returnSync.getUsers().get(j).getStatus());
 | 
			
		||||
					logger.info(getChats().get(k).getRecipient().getStatus().toString());
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sync.getMessages().clear();
 | 
			
		||||
		sync.getUsers().clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds the unread messages returned from the server in the latest sync to the
 | 
			
		||||
	 * right chats in the LocalDB.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param localDB
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void addUnreadMessagesToLocalDB() {
 | 
			
		||||
		Sync unreadMessages = unreadMessagesSync;
 | 
			
		||||
		for (int i = 0; i < unreadMessages.getMessages().size(); i++)
 | 
			
		||||
			for (int j = 0; j < getChats().size(); j++)
 | 
			
		||||
				if (getChats().get(j).getRecipient().getID() == unreadMessages.getMessages().get(i).getMetadata().getSender()) {
 | 
			
		||||
					getChats().get(j).appendMessage(unreadMessages.getMessages().get(i));
 | 
			
		||||
				}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Changes all messages with state {@code RECEIVED} of a specific chat to state
 | 
			
		||||
	 * {@code READ}.
 | 
			
		||||
	 * <br>
 | 
			
		||||
	 * Adds these messages to the {@code readMessages} {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param currentChat
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void setMessagesToRead(Chat currentChat) {
 | 
			
		||||
		for (int i = currentChat.getModel().size() - 1; i >= 0; --i)
 | 
			
		||||
			if (currentChat.getModel().get(i).getMetadata().getRecipient() != currentChat.getRecipient().getID())
 | 
			
		||||
				if (currentChat.getModel().get(i).getMetadata().getState() == MessageState.RECEIVED) {
 | 
			
		||||
					currentChat.getModel().get(i).getMetadata().setState(MessageState.READ);
 | 
			
		||||
					readMessages.getMessages().add(currentChat.getModel().get(i));
 | 
			
		||||
				} else break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Adds all messages with state {@code WAITING} from the {@link LocalDB} to the
 | 
			
		||||
	 * {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	private void addWaitingMessagesToSync() {
 | 
			
		||||
		for (Chat chat : getChats())
 | 
			
		||||
			for (int i = 0; i < chat.getModel().size(); i++)
 | 
			
		||||
				if (chat.getModel().get(i).getMetadata().getState() == MessageState.WAITING) {
 | 
			
		||||
					// addMessageToSync(localDB.getChats().get(i).getModel().get(j));
 | 
			
		||||
					logger.info("Got Waiting Message");
 | 
			
		||||
					sync.getMessages().add(chat.getModel().get(i));
 | 
			
		||||
				}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clears the {@code unreadMessagesSync} {@link Sync} object.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void clearUnreadMessagesSync() { unreadMessagesSync.getMessages().clear(); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return all saves {@link Chat} objects that list the client user as the
 | 
			
		||||
	 *         client
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 **/
 | 
			
		||||
	public List<Chat> getChats() { return chats; }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the {@link User} who initialized the local database
 | 
			
		||||
	 * @since Envoy v0.1-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public User getUser() { return sender; }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -226,7 +226,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
					.get();
 | 
			
		||||
 | 
			
		||||
				// Set all unread messages in the chat to read
 | 
			
		||||
				if (currentChat != null) { localDB.setMessagesToRead(currentChat); }
 | 
			
		||||
				readCurrentChat();
 | 
			
		||||
 | 
			
		||||
				client.setRecipient(user);
 | 
			
		||||
 | 
			
		||||
@@ -272,7 +272,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
 | 
			
		||||
			// Create and send message object
 | 
			
		||||
			final Message message = localDB.createMessage(messageEnterTextArea.getText(), currentChat.getRecipient());
 | 
			
		||||
			localDB.addWaitingMessageToLocalDB(message, currentChat);
 | 
			
		||||
			currentChat.appendMessage(message);
 | 
			
		||||
			messageList.setModel(currentChat.getModel());
 | 
			
		||||
 | 
			
		||||
			// Clear text field
 | 
			
		||||
@@ -309,7 +309,8 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Updates the data model and the ui every x seconds.
 | 
			
		||||
	 * Updates the data model and the UI repeatedly after a certain amount of
 | 
			
		||||
	 * time.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * @param timeout the amount of time that passes between two requests sent to
 | 
			
		||||
	 *                the server
 | 
			
		||||
@@ -322,9 +323,14 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
				// Synchronize
 | 
			
		||||
				localDB.applySync(
 | 
			
		||||
						client.sendSync(client.getSender().getID(), localDB.fillSync(client.getSender().getID())));
 | 
			
		||||
 | 
			
		||||
				// Process unread messages
 | 
			
		||||
				localDB.addUnreadMessagesToLocalDB();
 | 
			
		||||
				localDB.clearUnreadMessagesSync();
 | 
			
		||||
 | 
			
		||||
				// Mark unread messages as read when they are in the current chat
 | 
			
		||||
				readCurrentChat();
 | 
			
		||||
 | 
			
		||||
				// Update UI
 | 
			
		||||
				SwingUtilities
 | 
			
		||||
					.invokeLater(() -> { updateUserStates(); contentPane.revalidate(); contentPane.repaint(); });
 | 
			
		||||
@@ -338,4 +344,9 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
				if (userList.getModel().getElementAt(i).getID() == localDB.getChats().get(j).getRecipient().getID())
 | 
			
		||||
					userList.getModel().getElementAt(i).setStatus(localDB.getChats().get(j).getRecipient().getStatus());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Marks messages in the current chat as {@code READ}.
 | 
			
		||||
	 */
 | 
			
		||||
	private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user