Implemented message ID generation and generator requests
* Persisting IdGenerator in LocalDB * Added Client#requestIdGenerator() * Listening to MessageCreationEvents in ChatWindow
This commit is contained in:
		
							
								
								
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -28,7 +28,7 @@ | ||||
| 		<dependency> | ||||
| 			<groupId>com.github.informatik-ag-ngl</groupId> | ||||
| 			<artifactId>envoy-common</artifactId> | ||||
| 			<version>e5c67b8</version> | ||||
| 			<version>develop-SNAPSHOT</version> | ||||
| 		</dependency> | ||||
| 	</dependencies> | ||||
|  | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import javax.naming.TimeLimitExceededException; | ||||
|  | ||||
| import envoy.client.util.EnvoyLog; | ||||
| import envoy.data.*; | ||||
| import envoy.event.IdGeneratorRequest; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
| @@ -45,11 +46,13 @@ public class Client implements Closeable { | ||||
| 	 * an exception is thrown. | ||||
| 	 * | ||||
| 	 * @param credentials the login credentials of the user | ||||
| 	 * @param localDB     the local database used to persist the current | ||||
| 	 *                    {@link IdGenerator} | ||||
| 	 * @throws Exception if the online mode could not be entered or the request | ||||
| 	 *                   failed for some other reason | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void onlineInit(LoginCredentials credentials) throws Exception { | ||||
| 	public void onlineInit(LoginCredentials credentials, LocalDB localDB) throws Exception { | ||||
| 		// Establish TCP connection | ||||
| 		logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); | ||||
| 		socket = new Socket(config.getServer(), config.getPort()); | ||||
| @@ -84,21 +87,38 @@ public class Client implements Closeable { | ||||
|  | ||||
| 		// Register processors for message and status handling | ||||
| 		receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); | ||||
| 		// TODO: Status handling | ||||
|  | ||||
| 		// Process message ID generation | ||||
| 		receiver.registerProcessor(IdGenerator.class, localDB::setIdGenerator); | ||||
|  | ||||
| 		// Request a generator if none is present | ||||
| 		if (!localDB.hasIdGenerator() || !localDB.getIdGenerator().hasNext()) requestIdGenerator(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sends a message to the server. | ||||
| 	 *  | ||||
| 	 * | ||||
| 	 * @param message the message to send | ||||
| 	 * @throws IOException if the message does not reach the server | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void sendMessage(Message message) throws IOException { | ||||
| 		checkOnline(); | ||||
| 		SerializationUtils.writeBytesWithLength(message, socket.getOutputStream()); | ||||
| 		writeObject(message); | ||||
| 		message.nextStatus(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Requests a new {@link IdGenerator} from the server. | ||||
| 	 * | ||||
| 	 * @throws IOException if the request does not reach the server | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void requestIdGenerator() throws IOException { | ||||
| 		logger.info("Requesting new id generator..."); | ||||
| 		writeObject(new IdGeneratorRequest()); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return a {@code Map<String, User>} of all users on the server with their | ||||
| 	 *         user names as keys | ||||
| @@ -114,6 +134,11 @@ public class Client implements Closeable { | ||||
| 	@Override | ||||
| 	public void close() throws IOException { if (online) socket.close(); } | ||||
|  | ||||
| 	private void writeObject(Object obj) throws IOException { | ||||
| 		checkOnline(); | ||||
| 		SerializationUtils.writeBytesWithLength(obj, socket.getOutputStream()); | ||||
| 	} | ||||
|  | ||||
| 	private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); } | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -4,10 +4,15 @@ import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.util.*; | ||||
|  | ||||
| import envoy.data.IdGenerator; | ||||
| import envoy.data.User; | ||||
| import envoy.util.SerializationUtils; | ||||
|  | ||||
| /** | ||||
|  * Stored information about the current {@link User} and their {@link Chat}s. | ||||
|  * For message ID generation a {@link IdGenerator} is stored as well. | ||||
|  * These object are persisted inside a folder of the local file system.<br> | ||||
|  * <br> | ||||
|  * Project: <strong>envoy-client</strong><br> | ||||
|  * File: <strong>LocalDB.java</strong><br> | ||||
|  * Created: <strong>27.10.2019</strong><br> | ||||
| @@ -18,10 +23,11 @@ import envoy.util.SerializationUtils; | ||||
|  */ | ||||
| public class LocalDB { | ||||
|  | ||||
| 	private File				localDBDir, localDBFile, usersFile; | ||||
| 	private File				localDBDir, localDBFile, usersFile, idGeneratorFile; | ||||
| 	private User				user; | ||||
| 	private Map<String, User>	users	= new HashMap<>(); | ||||
| 	private List<Chat>			chats	= new ArrayList<>(); | ||||
| 	private IdGenerator			idGenerator; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructs an empty local database. To serialize any chats to the file | ||||
| @@ -37,7 +43,8 @@ public class LocalDB { | ||||
| 		// Initialize local database directory | ||||
| 		if (localDBDir.exists() && !localDBDir.isDirectory()) | ||||
| 			throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); | ||||
| 		usersFile = new File(localDBDir, "users.db"); | ||||
| 		usersFile		= new File(localDBDir, "users.db"); | ||||
| 		idGeneratorFile	= new File(localDBDir, "id_generator.db"); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -53,7 +60,8 @@ public class LocalDB { | ||||
|  | ||||
| 	/** | ||||
| 	 * Stores all users to the local database. If the client user is specified, the | ||||
| 	 * chats related to this user are stored as well. | ||||
| 	 * chats related to this user are stored as well. The message id generator will | ||||
| 	 * also be saved if present. | ||||
| 	 * | ||||
| 	 * @throws IOException if something went wrong during saving | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| @@ -63,12 +71,15 @@ public class LocalDB { | ||||
| 		SerializationUtils.write(usersFile, users); | ||||
|  | ||||
| 		// Save chats | ||||
| 		SerializationUtils.write(localDBFile, chats); | ||||
| 		if (user != null) SerializationUtils.write(localDBFile, chats); | ||||
|  | ||||
| 		// Save id generator | ||||
| 		if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads all users that are stored in the local database. | ||||
| 	 *  | ||||
| 	 * | ||||
| 	 * @throws IOException            if the loading process failed | ||||
| 	 * @throws ClassNotFoundException if the loading process failed | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| @@ -77,13 +88,25 @@ public class LocalDB { | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads all chats saved by Envoy for the client user. | ||||
| 	 *  | ||||
| 	 * | ||||
| 	 * @throws IOException            if the loading process failed | ||||
| 	 * @throws ClassNotFoundException if the loading process failed | ||||
| 	 * @since Envoy v0.1-alpha | ||||
| 	 */ | ||||
| 	public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads the message ID generator that is stored in the local database. If the | ||||
| 	 * file is not found, the exception is ignored. | ||||
| 	 * | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void loadIdGenerator() { | ||||
| 		try { | ||||
| 			idGenerator = SerializationUtils.read(idGeneratorFile, IdGenerator.class); | ||||
| 		} catch (ClassNotFoundException | IOException e) {} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return a {@code Map<String, User>} of all users stored locally with their | ||||
| 	 *         user names as keys | ||||
| @@ -119,4 +142,22 @@ public class LocalDB { | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| 	 */ | ||||
| 	public void setUser(User user) { this.user = user; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return the message ID generator | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public IdGenerator getIdGenerator() { return idGenerator; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @param idGenerator the message ID generator to set | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public void setIdGenerator(IdGenerator idGenerator) { this.idGenerator = idGenerator; } | ||||
|  | ||||
| 	/** | ||||
| 	 * @return {@code true} if an {@link IdGenerator} is present | ||||
| 	 * @since Envoy v0.3-alpha | ||||
| 	 */ | ||||
| 	public boolean hasIdGenerator() { return idGenerator != null; } | ||||
| } | ||||
| @@ -10,6 +10,7 @@ import javax.swing.*; | ||||
| import javax.swing.border.EmptyBorder; | ||||
|  | ||||
| import envoy.client.*; | ||||
| import envoy.client.event.MessageCreationEvent; | ||||
| import envoy.client.event.ThemeChangeEvent; | ||||
| import envoy.client.ui.list.ComponentList; | ||||
| import envoy.client.ui.settings.SettingsScreen; | ||||
| @@ -175,7 +176,9 @@ public class ChatWindow extends JFrame { | ||||
|  | ||||
| 				messageList.setModel(currentChat.getModel()); | ||||
| 				scrollPane.setChatOpened(true); | ||||
| 				contentPane.revalidate(); | ||||
|  | ||||
| 				revalidate(); | ||||
| 				repaint(); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| @@ -194,13 +197,20 @@ public class ChatWindow extends JFrame { | ||||
| 		contentPane.add(userList, gbc_userList); | ||||
| 		contentPane.revalidate(); | ||||
|  | ||||
| 		// Listen to theme changes | ||||
| 		EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); | ||||
|  | ||||
| 		// Listen to received messages | ||||
| 		EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> { | ||||
| 			Message message = ((MessageCreationEvent) evt).get(); | ||||
| 			localDB.getChats().stream().filter(c -> c.getRecipient().getId() == message.getRecipientId()).findFirst().get().appendMessage(message); | ||||
| 		}); | ||||
|  | ||||
| 		contentPane.revalidate(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Used to immediately reload the ChatWindow when settings were changed. | ||||
| 	 * Used to immediately reload the {@link ChatWindow} when settings were changed. | ||||
| 	 * | ||||
| 	 * @param theme the theme to change colors into | ||||
| 	 * @since Envoy v0.2-alpha | ||||
| @@ -247,7 +257,7 @@ public class ChatWindow extends JFrame { | ||||
| 		if (!messageEnterTextArea.getText().isEmpty()) try { | ||||
|  | ||||
| 			// Create message | ||||
| 			final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId()) | ||||
| 			final Message message = new MessageBuilder(localDB.getUser().getId(), currentChat.getRecipient().getId(), localDB.getIdGenerator()) | ||||
| 				.setText(messageEnterTextArea.getText()) | ||||
| 				.build(); | ||||
|  | ||||
| @@ -262,12 +272,17 @@ public class ChatWindow extends JFrame { | ||||
| 			// Clear text field | ||||
| 			messageEnterTextArea.setText(""); | ||||
|  | ||||
| 			// Update UI | ||||
| 			revalidate(); | ||||
| 			repaint(); | ||||
|  | ||||
| 			// Request a new id generator if all ids were used | ||||
| 			if (!localDB.getIdGenerator().hasNext()) client.requestIdGenerator(); | ||||
|  | ||||
| 		} catch (Exception e) { | ||||
| 			JOptionPane.showMessageDialog(this, | ||||
| 					"An exception occured while sending a message. See the log for more details.", | ||||
| 					"Exception occured", | ||||
| 					"Error sending message:\n" + e.toString(), | ||||
| 					"Message sending error", | ||||
| 					JOptionPane.ERROR_MESSAGE); | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
|   | ||||
| @@ -62,7 +62,7 @@ public class Startup { | ||||
| 			if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); | ||||
| 		} catch (Exception e) { | ||||
| 			JOptionPane | ||||
| 				.showMessageDialog(null, "Error loading configuration values: \n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); | ||||
| 				.showMessageDialog(null, "Error loading configuration values:\n" + e.toString(), "Configuration error", JOptionPane.ERROR_MESSAGE); | ||||
| 			System.exit(1); | ||||
| 			e.printStackTrace(); | ||||
| 		} | ||||
| @@ -97,7 +97,8 @@ public class Startup { | ||||
| 		Client client = new Client(); | ||||
| 		try { | ||||
| 			// Try entering online mode first | ||||
| 			client.onlineInit(credentials); | ||||
| 			localDB.loadIdGenerator(); | ||||
| 			client.onlineInit(credentials, localDB); | ||||
| 		} catch (Exception e1) { | ||||
| 			logger.warning("Could not connect to server. Trying offline mode..."); | ||||
| 			e1.printStackTrace(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user