Working on handshake mechanism with login
This commit is contained in:
		| @@ -1,21 +1,15 @@ | ||||
| package envoy.client; | ||||
|  | ||||
| import java.io.StringWriter; | ||||
| import java.util.HashMap; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.net.Socket; | ||||
| import java.util.Map; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| import javax.ws.rs.client.ClientBuilder; | ||||
| import javax.ws.rs.client.Entity; | ||||
| import javax.ws.rs.client.WebTarget; | ||||
| import javax.ws.rs.core.Response; | ||||
| import javax.xml.bind.JAXBContext; | ||||
| import javax.xml.bind.JAXBException; | ||||
| import javax.xml.bind.Marshaller; | ||||
|  | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.LoginCredentials; | ||||
| import envoy.data.User; | ||||
| import envoy.exception.EnvoyException; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
| @@ -29,43 +23,41 @@ import envoy.exception.EnvoyException; | ||||
|  */ | ||||
| public class Client { | ||||
|  | ||||
| 	private Config			config; | ||||
| 	private User			sender, recipient; | ||||
| 	private boolean			online			= false; | ||||
| 	private Socket	socket; | ||||
| 	private Config	config	= Config.getInstance(); | ||||
| 	private User	sender, recipient; | ||||
| 	private boolean	online; | ||||
|  | ||||
| 	private static final Logger logger = EnvoyLog.getLogger(Client.class.getSimpleName()); | ||||
|  | ||||
| 	/** | ||||
| 	 * Initializes the client. At this state, the client user has yet to be | ||||
| 	 * initialized, which can be done by calling {@link Client#onlineInit(String)}. | ||||
| 	 * | ||||
| 	 * @param config The {@link Config} instance to use in this client | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public Client(Config config) { this.config = config; } | ||||
|  | ||||
| 	/** | ||||
| 	 * Enters the online mode by acquiring a user ID from the server. | ||||
| 	 * | ||||
| 	 * @param userName the name of the client user | ||||
| 	 * @throws EnvoyException if the online mode could not be entered or the request | ||||
| 	 *                        failed for some other reason | ||||
| 	 * @param credentials the login credentials of the user | ||||
| 	 * @throws IOException if the online mode could not be entered or the request | ||||
| 	 *                     failed for some other reason | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void onlineInit(String userName) throws EnvoyException { | ||||
| 		sender	= getUser(userName); | ||||
| 		online	= true; | ||||
| 	} | ||||
| 	public void onlineInit(LoginCredentials credentials) throws IOException { | ||||
| 		logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); | ||||
| 		socket = new Socket(config.getServer(), config.getPort()); | ||||
| 		logger.info("Successfully connected to server."); | ||||
|  | ||||
| 	private <T, R> R post(String uri, T body, Class<R> responseBodyClass) { | ||||
| 		javax.ws.rs.client.Client	client			= ClientBuilder.newClient(); | ||||
| 		WebTarget					target			= client.target(uri); | ||||
| 		Response					response		= target.request().post(Entity.entity(body, "application/xml")); | ||||
| 		R							responseBody	= response.readEntity(responseBodyClass); | ||||
| 		response.close(); | ||||
| 		client.close(); | ||||
| 		// Write login credentials | ||||
| 		logger.finest("Sending login credentials..."); | ||||
| 		SerializationUtils.writeBytesWithLength(credentials, socket.getOutputStream()); | ||||
|  | ||||
| 		return responseBody; | ||||
| 		// Read response (user object) | ||||
| 		InputStream in = socket.getInputStream(); | ||||
|  | ||||
| 		// Read object | ||||
| 		try { | ||||
| 			sender = SerializationUtils.read(in, User.class); | ||||
| 		} catch (ClassNotFoundException e) { | ||||
| 			throw new IOException(e); | ||||
| 		} | ||||
|  | ||||
| 		online = true; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -74,106 +66,8 @@ public class Client { | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public Map<String, User> getUsers() { | ||||
| 		Sync	sendSync	= objectFactory.createSync(); | ||||
| 		User	user		= objectFactory.createUser(); | ||||
| 		user.setID(-1); | ||||
| 		sendSync.getUsers().add(user); | ||||
|  | ||||
| 		Sync returnSync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), | ||||
| 				sendSync, | ||||
| 				Sync.class); | ||||
|  | ||||
| 		Map<String, User> users = new HashMap<>(); | ||||
| 		returnSync.getUsers().forEach(u -> users.put(u.getName(), u)); | ||||
| 		return users; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Returns a {@link User} with a specific id by name. | ||||
| 	 * | ||||
| 	 * @param name - the name of the {@link User} | ||||
| 	 * @return a {@link User} with the specified name | ||||
| 	 * @throws EnvoyException if the server does not return the requested ID | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	private User getUser(String name) throws EnvoyException { | ||||
| 		// Create a sync with only a user with the requested name | ||||
| 		Sync	senderSync	= objectFactory.createSync(); | ||||
| 		User	user		= objectFactory.createUser(); | ||||
| 		user.setName(name); | ||||
| 		senderSync.getUsers().add(user); | ||||
|  | ||||
| 		try { | ||||
| 			Sync sync = post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), 0), | ||||
| 					senderSync, | ||||
| 					Sync.class); | ||||
|  | ||||
| 			// Expecting a single user with an ID | ||||
| 			if (sync.getUsers().size() == 1) { | ||||
| 				online = true; | ||||
| 				return sync.getUsers().get(0); | ||||
| 			} else throw new EnvoyException("Unexpected response from Envoy Server"); | ||||
| 		} catch (Exception e) { | ||||
| 			throw new EnvoyException("Could not connect to server", e); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sends the "sync" Sync Object to the server and gets a "returnSync" Sync | ||||
| 	 * Object as response. <br> | ||||
| 	 * It is also used to get the own sender at the start of the client | ||||
| 	 * (Client sends "sync" Sync Object with single user in it(name: the name | ||||
| 	 * entered at login, id: 0, UserStatus:null))<br> | ||||
| 	 * and to get a complete list of all users saved on the server. | ||||
| 	 * (Client sends "sync" Sync Object with single user in it(name: "" (empty), id: | ||||
| 	 * -1, UserStatus:null)) <br> | ||||
| 	 * This method also processes the response Sync Object. <br> | ||||
| 	 * It sorts its users and messages by specific variables and does certain things | ||||
| 	 * with them. <br> | ||||
| 	 * <br> | ||||
| 	 * Messages: <br> | ||||
| 	 * -State SENT: Update Local message(s) with State WAITING (add Message ID and | ||||
| 	 * change State to SENT). (server sends these informations to the client if | ||||
| 	 * message(s) with State WAITING were successfully sent to the server)<br> | ||||
| 	 * -State RECEIVED, SenderID != 0: Adds the unread Messages returned from the | ||||
| 	 * server in the latest sync to the "unreadMessagesSync" Sync Object. <br> | ||||
| 	 * -State RECEIVED, SenderID == 0: Update message(s) in localDB to state | ||||
| 	 * RECEIVED. | ||||
| 	 * (server sends these informations to the client if the other client received | ||||
| 	 * the message(s).) <br> | ||||
| 	 * -State READ: Update message(s) in the LocalDB to state READ. (server sends | ||||
| 	 * these informations to the client if the other client read | ||||
| 	 * the message(s).) <br> | ||||
| 	 * <br> | ||||
| 	 * Users: <br> | ||||
| 	 * Updating UserStatus of all users in LocalDB. (Server sends all users with | ||||
| 	 * their updated UserStatus to the client.) <br> | ||||
| 	 * | ||||
| 	 * @param userId the id of the {@link Client} who sends the {@link Sync} | ||||
| 	 * @param sync   the sync object (yet to be converted from java class to | ||||
| 	 *               sync.xml) | ||||
| 	 * @return a returnSync.xml file | ||||
| 	 * @throws EnvoyException if the client is not in online mode | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public Sync sendSync(long userId, Sync sync) throws EnvoyException { | ||||
| 		if(!isOnline()) | ||||
| 			throw new EnvoyException("Client is not in online mode"); | ||||
| 		// Print sync XML to console | ||||
| 		JAXBContext jc; | ||||
| 		try { | ||||
| 			jc = JAXBContext.newInstance("envoy.schema"); | ||||
| 			Marshaller m = jc.createMarshaller(); | ||||
| 			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); | ||||
| 			StringWriter stringWriter = new StringWriter(); | ||||
| 			m.marshal(sync, stringWriter); | ||||
| 			logger.fine("Sending sync:\n" + stringWriter.toString()); | ||||
| 		} catch (JAXBException e) { | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
|  | ||||
| 		// Send sync | ||||
| 		return post(String.format("%s:%d/envoy-server/rest/sync/syncData?userId=%d", config.getServer(), config.getPort(), userId), sync, Sync.class); | ||||
| 		// TODO | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -5,17 +5,9 @@ import java.io.IOException; | ||||
| import java.util.*; | ||||
| import java.util.logging.Logger; | ||||
|  | ||||
| import javax.naming.spi.ObjectFactory; | ||||
| import javax.xml.datatype.DatatypeConfigurationException; | ||||
| import javax.xml.datatype.DatatypeFactory; | ||||
|  | ||||
| import envoy.client.event.EventBus; | ||||
| import envoy.client.event.MessageCreationEvent; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.client.util.SerializationUtils; | ||||
| import envoy.data.Message; | ||||
| import envoy.data.User; | ||||
| import envoy.exception.EnvoyException; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
| @@ -33,13 +25,6 @@ public class LocalDB { | ||||
| 	private Map<String, User>	users	= new HashMap<>(); | ||||
| 	private List<Chat>			chats	= new ArrayList<>(); | ||||
|  | ||||
| 	private ObjectFactory	objectFactory	= new ObjectFactory(); | ||||
| 	private DatatypeFactory	datatypeFactory; | ||||
|  | ||||
| 	private Sync	unreadMessagesSync	= objectFactory.createSync(); | ||||
| 	private Sync	sync				= objectFactory.createSync(); | ||||
| 	private Sync	readMessages		= objectFactory.createSync(); | ||||
|  | ||||
| 	private static final Logger logger = EnvoyLog.getLogger(LocalDB.class.getSimpleName()); | ||||
|  | ||||
| 	/** | ||||
| @@ -53,12 +38,6 @@ public class LocalDB { | ||||
| 	public LocalDB(File localDBDir) throws IOException { | ||||
| 		this.localDBDir = localDBDir; | ||||
|  | ||||
| 		try { | ||||
| 			datatypeFactory = DatatypeFactory.newInstance(); | ||||
| 		} catch (DatatypeConfigurationException e) { | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
|  | ||||
| 		// Initialize local database directory | ||||
| 		if (localDBDir.exists() && !localDBDir.isDirectory()) | ||||
| 			throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); | ||||
| @@ -93,162 +72,181 @@ public class LocalDB { | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads all users that are stored in the local database. | ||||
| 	 * | ||||
| 	 * @throws EnvoyException if the loading process failed | ||||
| 	 *  | ||||
| 	 * @throws IOException            if the loading process failed | ||||
| 	 * @throws ClassNotFoundException if the loading process failed | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void loadUsers() throws EnvoyException { users = SerializationUtils.read(usersFile, HashMap.class); } | ||||
| 	public void loadUsers() throws ClassNotFoundException, IOException { users = SerializationUtils.read(usersFile, HashMap.class); } | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads all chats saved by Envoy for the client user. | ||||
| 	 * | ||||
| 	 * @throws EnvoyException if the loading process failed | ||||
| 	 *  | ||||
| 	 * @throws IOException            if the loading process failed | ||||
| 	 * @throws ClassNotFoundException if the loading process failed | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public void loadChats() throws EnvoyException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } | ||||
| 	public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } | ||||
|  | ||||
| 	/** | ||||
| 	 * Creates a {@link Sync} object filled with the changes that occurred to the | ||||
| 	 * local database since the last synchronization. | ||||
| 	 * | ||||
| 	 * @param userId the ID of the user that is synchronized by this client | ||||
| 	 * @return {@link Sync} object filled with the current changes | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public Sync fillSync(long userId) { | ||||
| 		addWaitingMessagesToSync(); | ||||
|  | ||||
| 		sync.getMessages().addAll(readMessages.getMessages()); | ||||
| 		readMessages.getMessages().clear(); | ||||
|  | ||||
| 		logger.finest(String.format("Filled sync with %d messages.", sync.getMessages().size())); | ||||
| 		return sync; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Applies the changes carried by a {@link Sync} object to the local database | ||||
| 	 * | ||||
| 	 * @param returnSync the {@link Sync} object to apply | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public void applySync(Sync returnSync) { | ||||
| 		for (int i = 0; i < returnSync.getMessages().size(); i++) { | ||||
|  | ||||
| 			// The message has an ID | ||||
| 			if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { | ||||
|  | ||||
| 				// Messages are processes differently corresponding to their state | ||||
| 				switch (returnSync.getMessages().get(i).getMetadata().getState()) { | ||||
| 					case SENT: | ||||
| 						// Update previously waiting and now sent messages that were assigned an ID by | ||||
| 						// the server | ||||
| 						sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); | ||||
| 						sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 						break; | ||||
| 					case RECEIVED: | ||||
| 						if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { | ||||
| 							// these are the unread Messages from the server | ||||
| 							unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); | ||||
|  | ||||
| 							// Create and dispatch message creation event | ||||
| 							EventBus.getInstance().dispatch(new MessageCreationEvent(returnSync.getMessages().get(i))); | ||||
| 						} else { | ||||
| 							// Update Messages in localDB to state RECEIVED | ||||
| 							for (Chat chat : getChats()) | ||||
| 								if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) | ||||
| 									for (int j = 0; j < chat.getModel().getSize(); j++) | ||||
| 									if (chat.getModel().get(j).getMetadata().getMessageId() == returnSync.getMessages() | ||||
| 										.get(i) | ||||
| 										.getMetadata() | ||||
| 										.getMessageId()) | ||||
| 										chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 						} | ||||
| 						break; | ||||
| 					case 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 (Chat chat : getChats()) | ||||
| 							if (chat.getRecipient().getId() == returnSync.getMessages().get(i).getMetadata().getRecipient()) { | ||||
| 								logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); | ||||
| 								for (int k = 0; k < chat.getModel().getSize(); k++) | ||||
| 									if (chat.getModel().get(k).getMetadata().getMessageId() == returnSync.getMessages() | ||||
| 										.get(i) | ||||
| 										.getMetadata() | ||||
| 										.getMessageId()) { | ||||
| 										logger.info("Message with ID: " + chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); | ||||
| 										chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 										logger.info("Message State is now: " + chat.getModel().get(k).getMetadata().getState()); | ||||
| 									} | ||||
| 							} | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Updating UserStatus of all users in LocalDB | ||||
| 		for (User user : returnSync.getUsers()) | ||||
| 			for (Chat chat : getChats()) | ||||
| 				if (user.getId() == chat.getRecipient().getId()) chat.getRecipient().setStatus(user.getStatus()); | ||||
|  | ||||
| 		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. | ||||
| 	 * | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public void addUnreadMessagesToLocalDB() { | ||||
| 		for (Message message : unreadMessagesSync.getMessages()) | ||||
| 			for (Chat chat : getChats()) | ||||
| 				if (message.getMetadata().getSender() == chat.getRecipient().getId()) { | ||||
| 					chat.appendMessage(message); | ||||
| 					break; | ||||
| 				} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 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 the {@link Chat} that was just opened | ||||
| 	 * @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) { | ||||
| 					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(); } | ||||
| 	// /** | ||||
| 	// * Creates a {@link Sync} object filled with the changes that occurred to the | ||||
| 	// * local database since the last synchronization. | ||||
| 	// * | ||||
| 	// * @param userId the ID of the user that is synchronized by this client | ||||
| 	// * @return {@link Sync} object filled with the current changes | ||||
| 	// * @since Envoy v0.1-alpha | ||||
| 	// */ | ||||
| 	// public Sync fillSync(long userId) { | ||||
| 	// addWaitingMessagesToSync(); | ||||
| 	// | ||||
| 	// sync.getMessages().addAll(readMessages.getMessages()); | ||||
| 	// readMessages.getMessages().clear(); | ||||
| 	// | ||||
| 	// logger.finest(String.format("Filled sync with %d messages.", | ||||
| 	// sync.getMessages().size())); | ||||
| 	// return sync; | ||||
| 	// } | ||||
| 	// | ||||
| 	// /** | ||||
| 	// * Applies the changes carried by a {@link Sync} object to the local database | ||||
| 	// * | ||||
| 	// * @param returnSync the {@link Sync} object to apply | ||||
| 	// * @since Envoy v0.1-alpha | ||||
| 	// */ | ||||
| 	// public void applySync(Sync returnSync) { | ||||
| 	// for (int i = 0; i < returnSync.getMessages().size(); i++) { | ||||
| 	// | ||||
| 	// // The message has an ID | ||||
| 	// if (returnSync.getMessages().get(i).getMetadata().getMessageId() != 0) { | ||||
| 	// | ||||
| 	// // Messages are processes differently corresponding to their state | ||||
| 	// switch (returnSync.getMessages().get(i).getMetadata().getState()) { | ||||
| 	// case SENT: | ||||
| 	// // Update previously waiting and now sent messages that were assigned an ID | ||||
| 	// by | ||||
| 	// // the server | ||||
| 	// sync.getMessages().get(i).getMetadata().setMessageId(returnSync.getMessages().get(i).getMetadata().getMessageId()); | ||||
| 	// sync.getMessages().get(i).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 	// break; | ||||
| 	// case RECEIVED: | ||||
| 	// if (returnSync.getMessages().get(i).getMetadata().getSender() != 0) { | ||||
| 	// // these are the unread Messages from the server | ||||
| 	// unreadMessagesSync.getMessages().add(returnSync.getMessages().get(i)); | ||||
| 	// | ||||
| 	// // Create and dispatch message creation event | ||||
| 	// EventBus.getInstance().dispatch(new | ||||
| 	// MessageCreationEvent(returnSync.getMessages().get(i))); | ||||
| 	// } else { | ||||
| 	// // Update Messages in localDB to state RECEIVED | ||||
| 	// for (Chat chat : getChats()) | ||||
| 	// if (chat.getRecipient().getId() == | ||||
| 	// returnSync.getMessages().get(i).getMetadata().getRecipient()) | ||||
| 	// for (int j = 0; j < chat.getModel().getSize(); j++) | ||||
| 	// if (chat.getModel().get(j).getMetadata().getMessageId() == | ||||
| 	// returnSync.getMessages() | ||||
| 	// .get(i) | ||||
| 	// .getMetadata() | ||||
| 	// .getMessageId()) | ||||
| 	// chat.getModel().get(j).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 	// } | ||||
| 	// break; | ||||
| 	// case 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 (Chat chat : getChats()) | ||||
| 	// if (chat.getRecipient().getId() == | ||||
| 	// returnSync.getMessages().get(i).getMetadata().getRecipient()) { | ||||
| 	// logger.info("Chat with: " + chat.getRecipient().getId() + "was selected."); | ||||
| 	// for (int k = 0; k < chat.getModel().getSize(); k++) | ||||
| 	// if (chat.getModel().get(k).getMetadata().getMessageId() == | ||||
| 	// returnSync.getMessages() | ||||
| 	// .get(i) | ||||
| 	// .getMetadata() | ||||
| 	// .getMessageId()) { | ||||
| 	// logger.info("Message with ID: " + | ||||
| 	// chat.getModel().get(k).getMetadata().getMessageId() + "was selected."); | ||||
| 	// chat.getModel().get(k).getMetadata().setState(returnSync.getMessages().get(i).getMetadata().getState()); | ||||
| 	// logger.info("Message State is now: " + | ||||
| 	// chat.getModel().get(k).getMetadata().getState()); | ||||
| 	// } | ||||
| 	// } | ||||
| 	// break; | ||||
| 	// } | ||||
| 	// } | ||||
| 	// } | ||||
| 	// | ||||
| 	// // Updating UserStatus of all users in LocalDB | ||||
| 	// for (User user : returnSync.getUsers()) | ||||
| 	// for (Chat chat : getChats()) | ||||
| 	// if (user.getId() == chat.getRecipient().getId()) | ||||
| 	// chat.getRecipient().setStatus(user.getStatus()); | ||||
| 	// | ||||
| 	// 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. | ||||
| 	// * | ||||
| 	// * @since Envoy v0.1-alpha | ||||
| 	// */ | ||||
| 	// public void addUnreadMessagesToLocalDB() { | ||||
| 	// for (Message message : unreadMessagesSync.getMessages()) | ||||
| 	// for (Chat chat : getChats()) | ||||
| 	// if (message.getMetadata().getSender() == chat.getRecipient().getId()) { | ||||
| 	// chat.appendMessage(message); | ||||
| 	// break; | ||||
| 	// } | ||||
| 	// } | ||||
| 	// | ||||
| 	// /** | ||||
| 	// * 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 the {@link Chat} that was just opened | ||||
| 	// * @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) | ||||
| 	// { | ||||
| 	// 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 a {@code Map<String, User>} of all users stored locally with their | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| package envoy.client; | ||||
|  | ||||
| import java.io.*; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.prefs.Preferences; | ||||
|  | ||||
| import envoy.client.ui.Color; | ||||
| import envoy.client.ui.Theme; | ||||
| import envoy.client.util.SerializationUtils; | ||||
| import envoy.exception.EnvoyException; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
|  * Manages all application settings, which are different objects that can be | ||||
| @@ -55,7 +55,7 @@ public class Settings { | ||||
| 		// Load settings from settings file | ||||
| 		try { | ||||
| 			items = SerializationUtils.read(settingsFile, HashMap.class); | ||||
| 		} catch (EnvoyException e) { | ||||
| 		} catch (ClassNotFoundException | IOException e) { | ||||
| 			items = new HashMap<>(); | ||||
| 		} | ||||
| 		supplementDefaults(); | ||||
| @@ -63,7 +63,7 @@ public class Settings { | ||||
| 		// Load themes from theme file | ||||
| 		try { | ||||
| 			themes = SerializationUtils.read(themeFile, HashMap.class); | ||||
| 		} catch (EnvoyException e1) { | ||||
| 		} catch (ClassNotFoundException | IOException e1) { | ||||
| 			themes = new HashMap<>(); | ||||
| 			setCurrentTheme("dark"); | ||||
| 		} | ||||
|   | ||||
| @@ -1,19 +0,0 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|  * File: <strong>Event.java</strong><br> | ||||
|  * Created: <strong>04.12.2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @param <T> the type of the Event | ||||
|  * @since Envoy v0.2-alpha | ||||
|  */ | ||||
| public interface Event<T> { | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the data associated with this event | ||||
| 	 */ | ||||
| 	T get(); | ||||
| } | ||||
|  | ||||
| @@ -1,81 +0,0 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * This class handles events by allowing {@link EventHandler} object to register | ||||
|  * themselves and then be notified about certain events dispatched by the event | ||||
|  * bus.<br> | ||||
|  * <br> | ||||
|  * The event bus is a singleton and can be used across the entire application to | ||||
|  * guarantee the propagation of events.<br> | ||||
|  * | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|  * File: <strong>EventBus.java</strong><br> | ||||
|  * Created: <strong>04.12.2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy v0.2-alpha | ||||
|  */ | ||||
| public class EventBus { | ||||
|  | ||||
| 	/** | ||||
| 	 * Contains all {@link EventHandler} instances registered at this | ||||
| 	 * {@link EventBus} as values mapped to by their supported {@link Event} | ||||
| 	 * classes. | ||||
| 	 */ | ||||
| 	private Map<Class<? extends Event<?>>, List<EventHandler>> handlers = new HashMap<>(); | ||||
|  | ||||
| 	/** | ||||
| 	 * The singleton instance of this {@link EventBus} that is used across the | ||||
| 	 * entire application. | ||||
| 	 */ | ||||
| 	private static EventBus eventBus = new EventBus(); | ||||
|  | ||||
| 	/** | ||||
| 	 * This constructor is not accessible from outside this class because a | ||||
| 	 * singleton instance of it is provided by the {@link EventBus#getInstance()} | ||||
| 	 * method. | ||||
| 	 */ | ||||
| 	private EventBus() {} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the singleton instance of the {@link EventBus} | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public static EventBus getInstance() { return eventBus; } | ||||
|  | ||||
| 	/** | ||||
| 	 * Registers an {@link EventHandler} to be notified when a | ||||
| 	 * {@link Event} of a certain type is dispatched. | ||||
| 	 * | ||||
| 	 * @param eventClass the class which the {@link EventHandler} is subscribed to | ||||
| 	 * @param handler    the {@link EventHandler} to register | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void register(Class<? extends Event<?>> eventClass, EventHandler handler) { | ||||
| 		if (!handlers.containsKey(eventClass)) handlers.put(eventClass, new ArrayList<>()); | ||||
| 		handlers.get(eventClass).add(handler); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Dispatches a {@link Event} to every {@link EventHandler} subscribed to it. | ||||
| 	 * | ||||
| 	 * @param event the {@link Event} to dispatch | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void dispatch(Event<?> event) { | ||||
| 		handlers.keySet().stream().filter(event.getClass()::isAssignableFrom).map(handlers::get).flatMap(List::stream).forEach(h -> h.handle(event)); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return a map of all {@link EventHandler} instances currently registered at | ||||
| 	 *         this {@link EventBus} with the {@link Event} classes they are | ||||
| 	 *         subscribed to as keys | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public Map<Class<? extends Event<?>>, List<EventHandler>> getHandlers() { return handlers; } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-clientChess</strong><br> | ||||
|  * File: <strong>EventHandler.javaEvent.java</strong><br> | ||||
|  * Created: <strong>04.12.2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  */ | ||||
| public interface EventHandler { | ||||
|  | ||||
| 	/** | ||||
| 	 * Consumes an event dispatched by the event bus. | ||||
| 	 * | ||||
| 	 * @param event The event dispatched by the event bus, only of supported type | ||||
| 	 */ | ||||
| 	void handle(Event<?> event); | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| import envoy.data.Message; | ||||
| import envoy.event.MessageEvent; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|   | ||||
| @@ -1,27 +0,0 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| import envoy.data.Message; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|  * File: <strong>MessageCreationEvent.java</strong><br> | ||||
|  * Created: <strong>4 Dec 2019</strong><br> | ||||
|  * | ||||
|  * @author Kai S. K. Engelbart | ||||
|  */ | ||||
| public class MessageEvent implements Event<Message> { | ||||
|  | ||||
| 	protected final Message message; | ||||
|  | ||||
| 	/** | ||||
| 	 * Initializes a {@link MessageEvent} conveying information about a | ||||
| 	 * {@link Message} object. | ||||
| 	 * | ||||
| 	 * @param message the {@link Message} object to attach to this event | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public MessageEvent(Message message) { this.message = message; } | ||||
|  | ||||
| 	@Override | ||||
| 	public Message get() { return message; } | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| import envoy.data.Message; | ||||
| import envoy.event.MessageEvent; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package envoy.client.event; | ||||
|  | ||||
| import envoy.client.ui.Theme; | ||||
| import envoy.event.Event; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|   | ||||
| @@ -10,13 +10,13 @@ import javax.swing.*; | ||||
| import javax.swing.border.EmptyBorder; | ||||
|  | ||||
| import envoy.client.*; | ||||
| import envoy.client.event.EventBus; | ||||
| import envoy.client.event.ThemeChangeEvent; | ||||
| import envoy.client.ui.settings.SettingsScreen; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.Message; | ||||
| import envoy.data.TextMessage; | ||||
| import envoy.data.User; | ||||
| import envoy.event.EventBus; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
| @@ -297,14 +297,15 @@ public class ChatWindow extends JFrame { | ||||
|  | ||||
| 				// Synchronize | ||||
| 				try { | ||||
| 					localDB.applySync(client.sendSync(client.getSender().getId(), localDB.fillSync(client.getSender().getId()))); | ||||
| 					// localDB.applySync(client.sendSync(client.getSender().getId(), | ||||
| 					// localDB.fillSync(client.getSender().getId()))); | ||||
| 				} catch (Exception e) { | ||||
| 					logger.log(Level.SEVERE, "Could not perform sync", e); | ||||
| 				} | ||||
|  | ||||
| 				// Process unread messages | ||||
| 				localDB.addUnreadMessagesToLocalDB(); | ||||
| 				localDB.clearUnreadMessagesSync(); | ||||
| 				// TODO: Process unread messages | ||||
| 				// localDB.addUnreadMessagesToLocalDB(); | ||||
| 				// localDB.clearUnreadMessagesSync(); | ||||
|  | ||||
| 				// Mark unread messages as read when they are in the current chat | ||||
| 				readCurrentChat(); | ||||
| @@ -325,7 +326,11 @@ public class ChatWindow extends JFrame { | ||||
| 	/** | ||||
| 	 * Marks messages in the current chat as {@code READ}. | ||||
| 	 */ | ||||
| 	private void readCurrentChat() { if (currentChat != null) { localDB.setMessagesToRead(currentChat); } } | ||||
| 	private void readCurrentChat() { | ||||
| 		if (currentChat != null) { | ||||
| 			// TODO: localDB.setMessagesToRead(currentChat); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the {@link Client} used by this {@link ChatWindow}. If the client is | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import javax.swing.SwingUtilities; | ||||
|  | ||||
| import envoy.client.*; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.LoginCredentials; | ||||
| import envoy.data.User; | ||||
| import envoy.exception.EnvoyException; | ||||
|  | ||||
| @@ -75,6 +76,9 @@ public class Startup { | ||||
| 			logger.severe("User name is not set or empty. Exiting..."); | ||||
| 			System.exit(1); | ||||
| 		} | ||||
| 		 | ||||
| 		// TODO: create dialog | ||||
| 		String pass = JOptionPane.showInputDialog("Enter password"); | ||||
|  | ||||
| 		// Initialize the local database | ||||
| 		LocalDB localDB; | ||||
| @@ -91,10 +95,10 @@ public class Startup { | ||||
|  | ||||
| 		// Acquire the client user (with ID) either from the server or from the local | ||||
| 		// database, which triggers offline mode | ||||
| 		Client client = new Client(config); | ||||
| 		Client client = new Client(); | ||||
| 		try { | ||||
| 			// Try entering online mode first | ||||
| 			client.onlineInit(userName); | ||||
| 			client.onlineInit(new LoginCredentials(userName, pass.toCharArray())); | ||||
| 		} catch (Exception e1) { | ||||
| 			logger.warning("Could not connect to server. Trying offline mode..."); | ||||
| 			try { | ||||
| @@ -120,8 +124,8 @@ public class Startup { | ||||
| 		// Initialize chats in local database | ||||
| 		try { | ||||
| 			localDB.initializeDBFile(); | ||||
| 			localDB.loadChats(); | ||||
| 		} catch (EnvoyException e) { | ||||
| 			// TODO: localDB.loadChats(); | ||||
| 		} catch (Exception e) { | ||||
| 			e.printStackTrace(); | ||||
| 			JOptionPane.showMessageDialog(null, | ||||
| 					"Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", | ||||
|   | ||||
| @@ -5,10 +5,10 @@ import java.awt.TrayIcon.MessageType; | ||||
| import java.awt.event.WindowAdapter; | ||||
| import java.awt.event.WindowEvent; | ||||
|  | ||||
| import envoy.client.event.EventBus; | ||||
| import envoy.client.event.MessageCreationEvent; | ||||
| import envoy.data.Message; | ||||
| import envoy.data.TextMessage; | ||||
| import envoy.event.EventBus; | ||||
| import envoy.exception.EnvoyException; | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -10,11 +10,11 @@ import java.util.logging.Logger; | ||||
| import javax.swing.*; | ||||
|  | ||||
| import envoy.client.Settings; | ||||
| import envoy.client.event.EventBus; | ||||
| import envoy.client.event.ThemeChangeEvent; | ||||
| import envoy.client.ui.PrimaryButton; | ||||
| import envoy.client.ui.Theme; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.event.EventBus; | ||||
|  | ||||
| /** | ||||
|  * This class provides the GUI to change the user specific settings.<br> | ||||
|   | ||||
| @@ -10,11 +10,11 @@ import java.util.logging.Logger; | ||||
| import javax.swing.*; | ||||
|  | ||||
| import envoy.client.Settings; | ||||
| import envoy.client.event.EventBus; | ||||
| import envoy.client.event.ThemeChangeEvent; | ||||
| import envoy.client.ui.Color; | ||||
| import envoy.client.ui.Theme; | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.event.EventBus; | ||||
|  | ||||
| /** | ||||
|  * Displays GUI components that allow changing the current {@Theme} and creating | ||||
|   | ||||
| @@ -1,57 +0,0 @@ | ||||
| package envoy.client.util; | ||||
|  | ||||
| import java.io.*; | ||||
|  | ||||
| import envoy.exception.EnvoyException; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>envoy-clientChess</strong><br> | ||||
|  * File: <strong>SerializationUtils.javaEvent.java</strong><br> | ||||
|  * Created: <strong>23.12.2019</strong><br> | ||||
|  *  | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy v0.3-alpha | ||||
|  */ | ||||
| public class SerializationUtils { | ||||
|  | ||||
| 	private SerializationUtils() {} | ||||
|  | ||||
| 	/** | ||||
| 	 * Deserializes an arbitrary {@link Serializable} object from a file. | ||||
| 	 *  | ||||
| 	 * @param <T>             the type of the object to deserialize | ||||
| 	 * @param file            the file deserialize from | ||||
| 	 * @param serializedClass the class of the object to deserialize | ||||
| 	 * @return the deserialized object | ||||
| 	 * @throws EnvoyException if an error occurred during deserialization | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public static <T extends Serializable> T read(File file, Class<T> serializedClass) throws EnvoyException { | ||||
| 		if (file == null) throw new NullPointerException("File is null"); | ||||
| 		try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { | ||||
| 			return serializedClass.cast(in.readObject()); | ||||
| 		} catch (ClassNotFoundException | IOException e) { | ||||
| 			throw new EnvoyException("Could not load serialized object", e); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Serializes an arbitrary object to a file. | ||||
| 	 *  | ||||
| 	 * @param file the file to serialize to | ||||
| 	 * @param obj  the object to serialize | ||||
| 	 * @throws IOException if an error occurred during serialization | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public static void write(File file, Object obj) throws IOException { | ||||
| 		if (file == null) throw new NullPointerException("File is null"); | ||||
| 		if (obj == null) throw new NullPointerException("Object to serialize is null"); | ||||
| 		if (!file.exists()) { | ||||
| 			file.getParentFile().mkdirs(); | ||||
| 			file.createNewFile(); | ||||
| 		} | ||||
| 		try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) { | ||||
| 			out.writeObject(obj); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user