diff --git a/pom.xml b/pom.xml index bf35cbb..0b5487d 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ com.github.informatik-ag-ngl envoy-common - e5c67b8 + develop-SNAPSHOT diff --git a/src/main/java/envoy/client/Client.java b/src/main/java/envoy/client/Client.java index 4885a92..935669f 100644 --- a/src/main/java/envoy/client/Client.java +++ b/src/main/java/envoy/client/Client.java @@ -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} 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"); } /** diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java index 2c40e65..7511d41 100644 --- a/src/main/java/envoy/client/LocalDB.java +++ b/src/main/java/envoy/client/LocalDB.java @@ -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.
+ *
* Project: envoy-client
* File: LocalDB.java
* Created: 27.10.2019
@@ -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 users = new HashMap<>(); private List 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} 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; } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index 3c4cdee..51c7d7f 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -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(); } diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 3e4692d..2fb9a3a 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -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();