Merge pull request #96 from informatik-ag-ngl/f/id_generation

Implemented ID generation on the client
This commit is contained in:
Kai S. K. Engelbart 2020-01-29 17:09:46 +01:00 committed by GitHub
commit 9323b0878f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 18 deletions

View File

@ -28,7 +28,7 @@
<dependency> <dependency>
<groupId>com.github.informatik-ag-ngl</groupId> <groupId>com.github.informatik-ag-ngl</groupId>
<artifactId>envoy-common</artifactId> <artifactId>envoy-common</artifactId>
<version>e5c67b8</version> <version>develop-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -11,6 +11,7 @@ import javax.naming.TimeLimitExceededException;
import envoy.client.util.EnvoyLog; import envoy.client.util.EnvoyLog;
import envoy.data.*; import envoy.data.*;
import envoy.event.IdGeneratorRequest;
import envoy.util.SerializationUtils; import envoy.util.SerializationUtils;
/** /**
@ -45,11 +46,13 @@ public class Client implements Closeable {
* an exception is thrown. * an exception is thrown.
* *
* @param credentials the login credentials of the user * @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 * @throws Exception if the online mode could not be entered or the request
* failed for some other reason * failed for some other reason
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void onlineInit(LoginCredentials credentials) throws Exception { public void onlineInit(LoginCredentials credentials, LocalDB localDB) throws Exception {
// Establish TCP connection // Establish TCP connection
logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort())); logger.info(String.format("Attempting connection to server %s:%d...", config.getServer(), config.getPort()));
socket = new Socket(config.getServer(), config.getPort()); socket = new Socket(config.getServer(), config.getPort());
@ -84,6 +87,13 @@ public class Client implements Closeable {
// Register processors for message and status handling // Register processors for message and status handling
receiver.registerProcessor(Message.class, new ReceivedMessageProcessor()); 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();
} }
/** /**
@ -94,11 +104,21 @@ public class Client implements Closeable {
* @since Envoy v0.3-alpha * @since Envoy v0.3-alpha
*/ */
public void sendMessage(Message message) throws IOException { public void sendMessage(Message message) throws IOException {
checkOnline(); writeObject(message);
SerializationUtils.writeBytesWithLength(message, socket.getOutputStream());
message.nextStatus(); 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 * @return a {@code Map<String, User>} of all users on the server with their
* user names as keys * user names as keys
@ -114,6 +134,11 @@ public class Client implements Closeable {
@Override @Override
public void close() throws IOException { if (online) socket.close(); } 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"); } private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); }
/** /**

View File

@ -4,10 +4,15 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import envoy.data.IdGenerator;
import envoy.data.User; import envoy.data.User;
import envoy.util.SerializationUtils; 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> * Project: <strong>envoy-client</strong><br>
* File: <strong>LocalDB.java</strong><br> * File: <strong>LocalDB.java</strong><br>
* Created: <strong>27.10.2019</strong><br> * Created: <strong>27.10.2019</strong><br>
@ -18,10 +23,11 @@ import envoy.util.SerializationUtils;
*/ */
public class LocalDB { public class LocalDB {
private File localDBDir, localDBFile, usersFile; private File localDBDir, localDBFile, usersFile, idGeneratorFile;
private User user; private User user;
private Map<String, User> users = new HashMap<>(); private Map<String, User> users = new HashMap<>();
private List<Chat> chats = new ArrayList<>(); private List<Chat> chats = new ArrayList<>();
private IdGenerator idGenerator;
/** /**
* Constructs an empty local database. To serialize any chats to the file * Constructs an empty local database. To serialize any chats to the file
@ -37,7 +43,8 @@ public class LocalDB {
// Initialize local database directory // Initialize local database directory
if (localDBDir.exists() && !localDBDir.isDirectory()) if (localDBDir.exists() && !localDBDir.isDirectory())
throw new IOException(String.format("LocalDBDir '%s' is not a directory!", localDBDir.getAbsolutePath())); 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 * 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 * @throws IOException if something went wrong during saving
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
@ -63,7 +71,10 @@ public class LocalDB {
SerializationUtils.write(usersFile, users); SerializationUtils.write(usersFile, users);
// Save chats // Save chats
SerializationUtils.write(localDBFile, chats); if (user != null) SerializationUtils.write(localDBFile, chats);
// Save id generator
if (hasIdGenerator()) SerializationUtils.write(idGeneratorFile, idGenerator);
} }
/** /**
@ -84,6 +95,18 @@ public class LocalDB {
*/ */
public void loadChats() throws ClassNotFoundException, IOException { chats = SerializationUtils.read(localDBFile, ArrayList.class); } 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 * @return a {@code Map<String, User>} of all users stored locally with their
* user names as keys * user names as keys
@ -119,4 +142,22 @@ public class LocalDB {
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public void setUser(User user) { this.user = user; } 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; }
} }

View File

@ -10,6 +10,7 @@ import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import envoy.client.*; import envoy.client.*;
import envoy.client.event.MessageCreationEvent;
import envoy.client.event.ThemeChangeEvent; import envoy.client.event.ThemeChangeEvent;
import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList;
import envoy.client.ui.settings.SettingsScreen; import envoy.client.ui.settings.SettingsScreen;
@ -175,7 +176,9 @@ public class ChatWindow extends JFrame {
messageList.setModel(currentChat.getModel()); messageList.setModel(currentChat.getModel());
scrollPane.setChatOpened(true); scrollPane.setChatOpened(true);
contentPane.revalidate();
revalidate();
repaint();
} }
}); });
@ -194,13 +197,20 @@ public class ChatWindow extends JFrame {
contentPane.add(userList, gbc_userList); contentPane.add(userList, gbc_userList);
contentPane.revalidate(); contentPane.revalidate();
// Listen to theme changes
EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get())); 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(); 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 * @param theme the theme to change colors into
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
@ -247,7 +257,7 @@ public class ChatWindow extends JFrame {
if (!messageEnterTextArea.getText().isEmpty()) try { if (!messageEnterTextArea.getText().isEmpty()) try {
// Create message // 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()) .setText(messageEnterTextArea.getText())
.build(); .build();
@ -262,12 +272,17 @@ public class ChatWindow extends JFrame {
// Clear text field // Clear text field
messageEnterTextArea.setText(""); messageEnterTextArea.setText("");
// Update UI
revalidate(); revalidate();
repaint(); repaint();
// Request a new id generator if all ids were used
if (!localDB.getIdGenerator().hasNext()) client.requestIdGenerator();
} catch (Exception e) { } catch (Exception e) {
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(this,
"An exception occured while sending a message. See the log for more details.", "Error sending message:\n" + e.toString(),
"Exception occured", "Message sending error",
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -62,7 +62,7 @@ public class Startup {
if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined"); if (!config.isInitialized()) throw new EnvoyException("Server or port are not defined");
} catch (Exception e) { } catch (Exception e) {
JOptionPane 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); System.exit(1);
e.printStackTrace(); e.printStackTrace();
} }
@ -97,7 +97,8 @@ public class Startup {
Client client = new Client(); Client client = new Client();
try { try {
// Try entering online mode first // Try entering online mode first
client.onlineInit(credentials); localDB.loadIdGenerator();
client.onlineInit(credentials, localDB);
} catch (Exception e1) { } catch (Exception e1) {
logger.warning("Could not connect to server. Trying offline mode..."); logger.warning("Could not connect to server. Trying offline mode...");
e1.printStackTrace(); e1.printStackTrace();