diff --git a/.gitignore b/.gitignore index b83d222..e12b13a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target/ +/localDB/ \ No newline at end of file diff --git a/src/main/java/envoy/client/Chat.java b/src/main/java/envoy/client/Chat.java index 19ad291..abeb226 100644 --- a/src/main/java/envoy/client/Chat.java +++ b/src/main/java/envoy/client/Chat.java @@ -1,12 +1,16 @@ package envoy.client; +import java.io.Serializable; + import javax.swing.DefaultListModel; import envoy.schema.Message; import envoy.schema.User; -public class Chat { +public class Chat implements Serializable { + private static final long serialVersionUID = -7751248474547242056L; + private User recipient; private DefaultListModel model = new DefaultListModel<>(); diff --git a/src/main/java/envoy/client/Config.java b/src/main/java/envoy/client/Config.java index ee9cf31..1d107ca 100644 --- a/src/main/java/envoy/client/Config.java +++ b/src/main/java/envoy/client/Config.java @@ -1,88 +1,108 @@ -package envoy.client; - -import java.util.Properties; - -/** - * Project: envoy-client
- * File: Config.java
- * Created: 12 Oct 2019
- * - * @author Kai S. K. Engelbart - * @since Envoy v0.1-alpha - */ -public class Config { - - private String server; - private int port; - - /** - * Defaults to the {@code server.properties} file for information. - * - * - * @param properties - The two options for internet connection - * server and port - * @since Envoy v0.1-alpha - */ - public void load(Properties properties) { - if (properties.containsKey("server")) server = properties.getProperty("server"); - if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); - } - - /** - * Sets the server and the port via command line properties --server/ -s and - * --port/ -p. - * - * @param args {@code --server} or {@code -s} followed by the specified URL - * and {@code --port} or {@code -p} followed by a 4-digit Integer - * @since Envoy v0.1-alpha - */ - public void load(String[] args) { - for (int i = 0; i < args.length; i++) - switch (args[i]) { - case "--server": - case "-s": - server = args[++i]; - break; - case "--port": - case "-p": - port = Integer.parseInt(args[++i]); - break; - } - } - - /** - * @return true if server and port are known. - * @since Envoy v0.1-alpha - */ - public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0; } - - /** - * @return the URL of our website - * @since Envoy v0.1-alpha - */ - public String getServer() { return server; } - - /** - * Changes the default URL. - * Exclusively meant for developing reasons. (localhost) - * - * @param server the URL where wish to host Envoy - * @since Envoy v0.1-alpha - */ - public void setServer(String server) { this.server = server; } - - /** - * @return the port at which Envoy is located in the Server - * @since Envoy v0.1-alpha - */ - public int getPort() { return port; } - - /** - * Changes the default port. - * Exclusively meant for developing reasons. (localhost) - * - * @param port the port where we wish to connect to {@code Envoy}. - * @since Envoy v0.1-alpha - */ - public void setPort(int port) { this.port = port; } -} \ No newline at end of file +package envoy.client; + +import java.io.File; +import java.util.Properties; + +/** + * Project: envoy-client
+ * File: Config.java
+ * Created: 12 Oct 2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha + */ +public class Config { + + private String server; + private int port; + private File localDB; + + /** + * Defaults to the {@code client.properties} file for information. + * + * @param properties a {@link Properties} object containing information about + * the server and port, as well as the path to the local + * database + * @since Envoy v0.1-alpha + */ + public void load(Properties properties) { + if (properties.containsKey("server")) server = properties.getProperty("server"); + if (properties.containsKey("port")) port = Integer.parseInt(properties.getProperty("port")); + localDB = new File(properties.getProperty("localDB", ".\\localDB")); + } + + /** + * Sets the server, port and localDB path via command line properties --server / + * -s, --port / -p and --localDB / -db. + * + * @param args the command line arguments to parse + * @since Envoy v0.1-alpha + */ + public void load(String[] args) { + for (int i = 0; i < args.length; i++) + switch (args[i]) { + case "--server": + case "-s": + server = args[++i]; + break; + case "--port": + case "-p": + port = Integer.parseInt(args[++i]); + break; + case "--localDB": + case "-db": + localDB = new File(args[++i]); + } + } + + /** + * @return {@code true} if server, port and localDB directory are known. + * @since Envoy v0.1-alpha + */ + public boolean isInitialized() { return server != null && !server.isEmpty() && port > 0 && port < 65566 && localDB != null; } + + /** + * @return the host name of the Envoy server + * @since Envoy v0.1-alpha + */ + public String getServer() { return server; } + + /** + * Changes the default server host name. + * Exclusively intended for development purposes. + * + * @param server the host name of the Envoy server + * @since Envoy v0.1-alpha + */ + public void setServer(String server) { this.server = server; } + + /** + * @return the port at which the Envoy server is located on the host + * @since Envoy v0.1-alpha + */ + public int getPort() { return port; } + + /** + * Changes the default port. + * Exclusively intended for development purposes. + * + * @param port the port where an Envoy server is located + * @since Envoy v0.1-alpha + */ + public void setPort(int port) { this.port = port; } + + /** + * @return the local database specific to the client user + * @since Envoy v0.1-alpha + **/ + public File getLocalDB() { return localDB; } + + /** + * Changes the default local database. + * Exclusively intended for development purposes. + * + * @param the file containing the local database + * @since Envoy v0.1-alpha + **/ + public void setLocalDB(File localDB) { this.localDB = localDB; } +} diff --git a/src/main/java/envoy/client/LocalDB.java b/src/main/java/envoy/client/LocalDB.java new file mode 100644 index 0000000..d7b3409 --- /dev/null +++ b/src/main/java/envoy/client/LocalDB.java @@ -0,0 +1,96 @@ +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.util.ArrayList; +import java.util.List; + +import envoy.exception.EnvoyException; +import envoy.schema.User; + +/** + * Project: envoy-client
+ * File: LocalDB.java
+ * Created: 27.10.2019
+ * + * @author Kai S. K. Engelbart + * @since Envoy v0.1-alpha + */ +public class LocalDB { + + private File localDB; + private User sender; + private List chats = new ArrayList<>(); + + /** + * Constructs an empty local database. + * + * @param sender the user that is logged in with this client + * @since Envoy v0.1-alpha + **/ + public LocalDB(User sender) { this.sender = sender; } + + /** + * 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(); + System.err.println("unable to save the messages"); + } + try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(localDB))) { + out.writeObject(chats); + } catch (IOException ex) { + ex.printStackTrace(); + System.err.println("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) obj; + } catch (ClassNotFoundException | IOException e) { + throw new EnvoyException(e); + } + } + + /** + * @return all saves {@link Chat} objects that list the client user as the + * sender + * @since Envoy v0.1-alpha + **/ + public List getChats() { return chats; } +} diff --git a/src/main/java/envoy/client/ui/ChatWindow.java b/src/main/java/envoy/client/ui/ChatWindow.java index dd7ff5e..5f79b13 100644 --- a/src/main/java/envoy/client/ui/ChatWindow.java +++ b/src/main/java/envoy/client/ui/ChatWindow.java @@ -6,8 +6,8 @@ import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; -import java.util.ArrayList; -import java.util.List; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import javax.swing.DefaultListModel; import javax.swing.JButton; @@ -25,6 +25,7 @@ import javax.swing.border.EmptyBorder; import envoy.client.Chat; import envoy.client.Client; +import envoy.client.LocalDB; import envoy.schema.Message; import envoy.schema.Messages; import envoy.schema.User; @@ -46,20 +47,28 @@ public class ChatWindow extends JFrame { private JPanel contentPane = new JPanel(); - private Client client; + private Client client; + private LocalDB localDB; - private JList userList = new JList<>(); - private List partnerChatList = new ArrayList(); + private JList userList = new JList<>(); private Chat currentChat; - public ChatWindow(Client client) { - this.client = client; + public ChatWindow(Client client, LocalDB localDB) { + this.client = client; + this.localDB = localDB; setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 600, 800); setTitle("Envoy"); setLocationRelativeTo(null); + // Save chats when window closes + addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { localDB.saveToLocalDB(); } + }); + contentPane.setBackground(new Color(0, 0, 0)); contentPane.setForeground(Color.white); contentPane.setBorder(new EmptyBorder(0, 5, 0, 0)); @@ -191,7 +200,7 @@ public class ChatWindow extends JFrame { final User user = selectedUserList.getSelectedValue(); client.setRecipient(user); - currentChat = partnerChatList.stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); + currentChat = localDB.getChats().stream().filter(chat -> chat.getRecipient().getID() == user.getID()).findFirst().get(); client.setRecipient(user); @@ -232,7 +241,13 @@ public class ChatWindow extends JFrame { new Thread(() -> { Users users = client.getUsersListXml(); DefaultListModel userListModel = new DefaultListModel<>(); - users.getUser().forEach(user -> { userListModel.addElement(user); partnerChatList.add(new Chat(user)); }); + users.getUser().forEach(user -> { + userListModel.addElement(user); + + // Check if user exists in local DB + if (localDB.getChats().stream().filter(c -> c.getRecipient().getID() == user.getID()).count() == 0) + localDB.getChats().add(new Chat(user)); + }); SwingUtilities.invokeLater(() -> userList.setModel(userListModel)); }).start(); } @@ -247,9 +262,9 @@ public class ChatWindow extends JFrame { new Timer(timeout, (evt) -> { Messages unreadMessages = client.getUnreadMessages(client.getSender().getID()); for (int i = 0; i < unreadMessages.getMessage().size(); i++) - for (int j = 0; j < partnerChatList.size(); j++) - if (partnerChatList.get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) - partnerChatList.get(j).appendMessage(unreadMessages.getMessage().get(i)); + for (int j = 0; j < localDB.getChats().size(); j++) + if (localDB.getChats().get(j).getRecipient().getID() == unreadMessages.getMessage().get(i).getMetaData().getSender()) + localDB.getChats().get(j).appendMessage(unreadMessages.getMessage().get(i)); }).start(); } } \ No newline at end of file diff --git a/src/main/java/envoy/client/ui/Startup.java b/src/main/java/envoy/client/ui/Startup.java index 08e7fd3..4f72026 100644 --- a/src/main/java/envoy/client/ui/Startup.java +++ b/src/main/java/envoy/client/ui/Startup.java @@ -8,6 +8,8 @@ import javax.swing.JOptionPane; import envoy.client.Client; import envoy.client.Config; +import envoy.client.LocalDB; +import envoy.exception.EnvoyException; /** * Starts the Envoy client and prompts the user to enter their name. @@ -30,7 +32,7 @@ public class Startup { ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { Properties configProperties = new Properties(); - configProperties.load(loader.getResourceAsStream("server.properties")); + configProperties.load(loader.getResourceAsStream("client.properties")); config.load(configProperties); } catch (IOException e) { e.printStackTrace(); @@ -47,11 +49,21 @@ public class Startup { System.err.println("User name is not set or empty. Exiting..."); System.exit(1); } - Client client = new Client(config, userName); + Client client = new Client(config, userName); + LocalDB localDB = new LocalDB(client.getSender()); + try { + localDB.initializeDBFile(config.getLocalDB()); + } catch (EnvoyException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(null, + "Error while loading local database: " + e.toString() + "\nChats will not be stored locally.", + "Local DB error", + JOptionPane.WARNING_MESSAGE); + } EventQueue.invokeLater(() -> { try { - ChatWindow frame = new ChatWindow(client); + ChatWindow frame = new ChatWindow(client, localDB); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/resources/client.properties b/src/main/resources/client.properties new file mode 100644 index 0000000..2641927 --- /dev/null +++ b/src/main/resources/client.properties @@ -0,0 +1,3 @@ +server=http://kske.feste-ip.net +port=43315 +localDB=.\\localDB diff --git a/src/main/resources/server.properties b/src/main/resources/server.properties deleted file mode 100644 index 6b0ae8f..0000000 --- a/src/main/resources/server.properties +++ /dev/null @@ -1,2 +0,0 @@ -server=http://kske.feste-ip.net -port=43315 \ No newline at end of file